diff --git a/crates/biome_graphql_parser/src/parser/definitions/fragment.rs b/crates/biome_graphql_parser/src/parser/definitions/fragment.rs new file mode 100644 index 000000000000..7f850cefe51a --- /dev/null +++ b/crates/biome_graphql_parser/src/parser/definitions/fragment.rs @@ -0,0 +1,50 @@ +use crate::parser::{ + directive::DirectiveList, + parse_error::{expected_name, expected_named_type}, + parse_name, + r#type::parse_named_type, + GraphqlParser, +}; +use biome_graphql_syntax::{GraphqlSyntaxKind::*, T}; +use biome_parser::{ + parse_lists::ParseNodeList, parsed_syntax::ParsedSyntax, prelude::ParsedSyntax::*, + CompletedMarker, Parser, +}; + +use super::operation::parse_selection_set; + +#[inline] +pub(crate) fn parse_fragment_definition(p: &mut GraphqlParser) -> ParsedSyntax { + if !is_at_fragment_definition(p) { + return Absent; + } + + let m = p.start(); + p.bump(T![fragment]); + + parse_name(p).or_add_diagnostic(p, expected_name); + parse_type_condition(p); + + DirectiveList.parse_list(p); + parse_selection_set(p).ok(); + + Present(m.complete(p, GRAPHQL_FRAGMENT_DEFINITION)) +} + +#[inline] +pub(crate) fn parse_type_condition(p: &mut GraphqlParser) -> CompletedMarker { + let m = p.start(); + p.expect(T![on]); + parse_named_type(p).or_add_diagnostic(p, expected_named_type); + m.complete(p, GRAPHQL_TYPE_CONDITION) +} + +#[inline] +pub(crate) fn is_at_fragment_definition(p: &GraphqlParser<'_>) -> bool { + p.at(T![fragment]) +} + +#[inline] +pub(crate) fn is_at_type_condition(p: &GraphqlParser<'_>) -> bool { + p.at(T![on]) +} diff --git a/crates/biome_graphql_parser/src/parser/definitions/mod.rs b/crates/biome_graphql_parser/src/parser/definitions/mod.rs index 71499c29df10..df00c3466471 100644 --- a/crates/biome_graphql_parser/src/parser/definitions/mod.rs +++ b/crates/biome_graphql_parser/src/parser/definitions/mod.rs @@ -1,3 +1,4 @@ +mod fragment; mod operation; use crate::parser::{parse_error::expected_any_definition, GraphqlParser}; @@ -7,7 +8,10 @@ use biome_parser::{ prelude::ParsedSyntax::*, Parser, }; -use self::operation::{is_at_operation, parse_operation_definition}; +use self::{ + fragment::{is_at_fragment_definition, parse_fragment_definition}, + operation::{is_at_operation, parse_operation_definition}, +}; pub(crate) use operation::is_at_selection_set_end; struct DefinitionListParseRecovery; @@ -50,15 +54,18 @@ impl ParseNodeList for DefinitionList { #[inline] fn parse_definition(p: &mut GraphqlParser) -> ParsedSyntax { - match p.cur() { - // TODO: parse any definition - _ if is_at_operation(p) => parse_operation_definition(p), - _ => Absent, + // TODO: parse any definition + if is_at_operation(p) { + parse_operation_definition(p) + } else if is_at_fragment_definition(p) { + parse_fragment_definition(p) + } else { + Absent } } #[inline] fn is_at_definition(p: &GraphqlParser<'_>) -> bool { // TODO: recover at any definition - is_at_operation(p) + is_at_operation(p) || is_at_fragment_definition(p) } diff --git a/crates/biome_graphql_parser/src/parser/definitions/operation.rs b/crates/biome_graphql_parser/src/parser/definitions/operation.rs index 465b958efc14..c88cbdde7cc0 100644 --- a/crates/biome_graphql_parser/src/parser/definitions/operation.rs +++ b/crates/biome_graphql_parser/src/parser/definitions/operation.rs @@ -3,11 +3,11 @@ use crate::parser::{ directive::{is_at_directive, DirectiveList}, is_at_name, parse_error::{ - expected_any_selection, expected_name, expected_named_type, expected_type, expected_value, + expected_any_selection, expected_name, expected_type, expected_value, expected_variable_definition, }, parse_name, - r#type::{parse_named_type, parse_type}, + r#type::parse_type, value::parse_value, variable::{is_at_variable, parse_variable}, GraphqlParser, @@ -21,7 +21,10 @@ use biome_parser::{ prelude::ParsedSyntax::*, token_set, Parser, TokenSet, }; -use super::is_at_definition; +use super::{ + fragment::{is_at_type_condition, parse_type_condition}, + is_at_definition, +}; const OPERATION_TYPE: TokenSet = token_set![T![query], T![mutation], T![subscription]]; @@ -136,7 +139,7 @@ pub(crate) fn parse_operation_definition(p: &mut GraphqlParser) -> ParsedSyntax } #[inline] -fn parse_selection_set(p: &mut GraphqlParser) -> ParsedSyntax { +pub(crate) fn parse_selection_set(p: &mut GraphqlParser) -> ParsedSyntax { let m = p.start(); p.expect(T!['{']); SelectionList.parse_list(p); @@ -204,11 +207,8 @@ fn parse_fragment(p: &mut GraphqlParser) -> ParsedSyntax { DirectiveList.parse_list(p); Present(m.complete(p, GRAPHQL_FRAGMENT_SPREAD)) } else { - if p.at(T![on]) { - let m = p.start(); - p.bump(T![on]); - parse_named_type(p).or_add_diagnostic(p, expected_named_type); - m.complete(p, GRAPHQL_TYPE_CONDITION); + if is_at_type_condition(p) { + parse_type_condition(p); } DirectiveList.parse_list(p); parse_selection_set(p).ok(); diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql new file mode 100644 index 000000000000..428657862e1f --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql @@ -0,0 +1,14 @@ +fragmen friendFields on User { + id + name +} + +fragment friendFields User @deprecated { + id + name +} + +fragment friendFields o User @deprecated { + id + name +} diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql.snap b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql.snap new file mode 100644 index 000000000000..20be3a9c1ee4 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/fragment.graphql.snap @@ -0,0 +1,358 @@ +--- +source: crates/biome_graphql_parser/tests/spec_test.rs +expression: snapshot +--- +## Input +```graphql +fragmen friendFields on User { + id + name +} + +fragment friendFields User @deprecated { + id + name +} + +fragment friendFields o User @deprecated { + id + name +} + +``` + +## AST + +``` +GraphqlRoot { + bom_token: missing (optional), + definitions: GraphqlDefinitionList [ + GraphqlBogusDefinition { + items: [ + GRAPHQL_NAME@0..8 "fragmen" [] [Whitespace(" ")], + GRAPHQL_NAME@8..21 "friendFields" [] [Whitespace(" ")], + ON_KW@21..24 "on" [] [Whitespace(" ")], + GRAPHQL_NAME@24..29 "User" [] [Whitespace(" ")], + ], + }, + GraphqlSelectionSet { + l_curly_token: L_CURLY@29..30 "{" [] [], + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@30..35 "id" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@35..42 "name" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + ], + r_curly_token: R_CURLY@42..44 "}" [Newline("\n")] [], + }, + GraphqlFragmentDefinition { + fragment_token: FRAGMENT_KW@44..55 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + name: GraphqlName { + value_token: GRAPHQL_NAME@55..68 "friendFields" [] [Whitespace(" ")], + }, + type_condition: GraphqlTypeCondition { + on_token: missing (required), + ty: GraphqlNamedType { + name: GraphqlName { + value_token: GRAPHQL_NAME@68..73 "User" [] [Whitespace(" ")], + }, + }, + }, + directives: GraphqlDirectiveList [ + GraphqlDirective { + at_token: AT@73..74 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@74..85 "deprecated" [] [Whitespace(" ")], + }, + arguments: missing (optional), + }, + ], + selection_set: GraphqlSelectionSet { + l_curly_token: L_CURLY@85..86 "{" [] [], + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@86..91 "id" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@91..98 "name" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + ], + r_curly_token: R_CURLY@98..100 "}" [Newline("\n")] [], + }, + }, + GraphqlFragmentDefinition { + fragment_token: FRAGMENT_KW@100..111 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + name: GraphqlName { + value_token: GRAPHQL_NAME@111..124 "friendFields" [] [Whitespace(" ")], + }, + type_condition: GraphqlTypeCondition { + on_token: missing (required), + ty: GraphqlNamedType { + name: GraphqlName { + value_token: GRAPHQL_NAME@124..126 "o" [] [Whitespace(" ")], + }, + }, + }, + directives: GraphqlDirectiveList [], + selection_set: GraphqlSelectionSet { + l_curly_token: missing (required), + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@126..131 "User" [] [Whitespace(" ")], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [ + GraphqlDirective { + at_token: AT@131..132 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@132..143 "deprecated" [] [Whitespace(" ")], + }, + arguments: missing (optional), + }, + ], + selection_set: GraphqlSelectionSet { + l_curly_token: L_CURLY@143..144 "{" [] [], + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@144..149 "id" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@149..156 "name" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + ], + r_curly_token: R_CURLY@156..158 "}" [Newline("\n")] [], + }, + }, + ], + r_curly_token: missing (required), + }, + }, + ], + eof_token: EOF@158..159 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: GRAPHQL_ROOT@0..159 + 0: (empty) + 1: GRAPHQL_DEFINITION_LIST@0..158 + 0: GRAPHQL_BOGUS_DEFINITION@0..29 + 0: GRAPHQL_NAME@0..8 "fragmen" [] [Whitespace(" ")] + 1: GRAPHQL_NAME@8..21 "friendFields" [] [Whitespace(" ")] + 2: ON_KW@21..24 "on" [] [Whitespace(" ")] + 3: GRAPHQL_NAME@24..29 "User" [] [Whitespace(" ")] + 1: GRAPHQL_SELECTION_SET@29..44 + 0: L_CURLY@29..30 "{" [] [] + 1: GRAPHQL_SELECTION_LIST@30..42 + 0: GRAPHQL_FIELD@30..35 + 0: (empty) + 1: GRAPHQL_NAME@30..35 + 0: GRAPHQL_NAME@30..35 "id" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@35..35 + 4: (empty) + 1: GRAPHQL_FIELD@35..42 + 0: (empty) + 1: GRAPHQL_NAME@35..42 + 0: GRAPHQL_NAME@35..42 "name" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@42..42 + 4: (empty) + 2: R_CURLY@42..44 "}" [Newline("\n")] [] + 2: GRAPHQL_FRAGMENT_DEFINITION@44..100 + 0: FRAGMENT_KW@44..55 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: GRAPHQL_NAME@55..68 + 0: GRAPHQL_NAME@55..68 "friendFields" [] [Whitespace(" ")] + 2: GRAPHQL_TYPE_CONDITION@68..73 + 0: (empty) + 1: GRAPHQL_NAMED_TYPE@68..73 + 0: GRAPHQL_NAME@68..73 + 0: GRAPHQL_NAME@68..73 "User" [] [Whitespace(" ")] + 3: GRAPHQL_DIRECTIVE_LIST@73..85 + 0: GRAPHQL_DIRECTIVE@73..85 + 0: AT@73..74 "@" [] [] + 1: GRAPHQL_NAME@74..85 + 0: GRAPHQL_NAME@74..85 "deprecated" [] [Whitespace(" ")] + 2: (empty) + 4: GRAPHQL_SELECTION_SET@85..100 + 0: L_CURLY@85..86 "{" [] [] + 1: GRAPHQL_SELECTION_LIST@86..98 + 0: GRAPHQL_FIELD@86..91 + 0: (empty) + 1: GRAPHQL_NAME@86..91 + 0: GRAPHQL_NAME@86..91 "id" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@91..91 + 4: (empty) + 1: GRAPHQL_FIELD@91..98 + 0: (empty) + 1: GRAPHQL_NAME@91..98 + 0: GRAPHQL_NAME@91..98 "name" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@98..98 + 4: (empty) + 2: R_CURLY@98..100 "}" [Newline("\n")] [] + 3: GRAPHQL_FRAGMENT_DEFINITION@100..158 + 0: FRAGMENT_KW@100..111 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: GRAPHQL_NAME@111..124 + 0: GRAPHQL_NAME@111..124 "friendFields" [] [Whitespace(" ")] + 2: GRAPHQL_TYPE_CONDITION@124..126 + 0: (empty) + 1: GRAPHQL_NAMED_TYPE@124..126 + 0: GRAPHQL_NAME@124..126 + 0: GRAPHQL_NAME@124..126 "o" [] [Whitespace(" ")] + 3: GRAPHQL_DIRECTIVE_LIST@126..126 + 4: GRAPHQL_SELECTION_SET@126..158 + 0: (empty) + 1: GRAPHQL_SELECTION_LIST@126..158 + 0: GRAPHQL_FIELD@126..158 + 0: (empty) + 1: GRAPHQL_NAME@126..131 + 0: GRAPHQL_NAME@126..131 "User" [] [Whitespace(" ")] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@131..143 + 0: GRAPHQL_DIRECTIVE@131..143 + 0: AT@131..132 "@" [] [] + 1: GRAPHQL_NAME@132..143 + 0: GRAPHQL_NAME@132..143 "deprecated" [] [Whitespace(" ")] + 2: (empty) + 4: GRAPHQL_SELECTION_SET@143..158 + 0: L_CURLY@143..144 "{" [] [] + 1: GRAPHQL_SELECTION_LIST@144..156 + 0: GRAPHQL_FIELD@144..149 + 0: (empty) + 1: GRAPHQL_NAME@144..149 + 0: GRAPHQL_NAME@144..149 "id" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@149..149 + 4: (empty) + 1: GRAPHQL_FIELD@149..156 + 0: (empty) + 1: GRAPHQL_NAME@149..156 + 0: GRAPHQL_NAME@149..156 "name" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@156..156 + 4: (empty) + 2: R_CURLY@156..158 "}" [Newline("\n")] [] + 2: (empty) + 2: EOF@158..159 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +fragment.graphql:1:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a definition but instead found 'fragmen friendFields on User'. + + > 1 │ fragmen friendFields on User { + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 2 │ id + 3 │ name + + i Expected a definition here. + + > 1 │ fragmen friendFields on User { + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 2 │ id + 3 │ name + +fragment.graphql:6:23 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `on` but instead found `User` + + 4 │ } + 5 │ + > 6 │ fragment friendFields User @deprecated { + │ ^^^^ + 7 │ id + 8 │ name + + i Remove User + +fragment.graphql:11:23 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `on` but instead found `o` + + 9 │ } + 10 │ + > 11 │ fragment friendFields o User @deprecated { + │ ^ + 12 │ id + 13 │ name + + i Remove o + +fragment.graphql:11:25 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `{` but instead found `User` + + 9 │ } + 10 │ + > 11 │ fragment friendFields o User @deprecated { + │ ^^^^ + 12 │ id + 13 │ name + + i Remove User + +fragment.graphql:15:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `}` but instead the file ends + + 13 │ name + 14 │ } + > 15 │ + │ + + i the file ends here + + 13 │ name + 14 │ } + > 15 │ + │ + +``` diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql new file mode 100644 index 000000000000..2d0189f6f6a7 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql @@ -0,0 +1,11 @@ +fragment friendFields on User { + id + name + profilePic(size: 50) +} + +fragment friendFields on User @deprecated { + id + name + profilePic(size: 50) +} diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql.snap b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql.snap new file mode 100644 index 000000000000..3a4bebe93625 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/fragment.graphql.snap @@ -0,0 +1,265 @@ +--- +source: crates/biome_graphql_parser/tests/spec_test.rs +expression: snapshot +--- +## Input +```graphql +fragment friendFields on User { + id + name + profilePic(size: 50) +} + +fragment friendFields on User @deprecated { + id + name + profilePic(size: 50) +} + +``` + +## AST + +``` +GraphqlRoot { + bom_token: missing (optional), + definitions: GraphqlDefinitionList [ + GraphqlFragmentDefinition { + fragment_token: FRAGMENT_KW@0..9 "fragment" [] [Whitespace(" ")], + name: GraphqlName { + value_token: GRAPHQL_NAME@9..22 "friendFields" [] [Whitespace(" ")], + }, + type_condition: GraphqlTypeCondition { + on_token: ON_KW@22..25 "on" [] [Whitespace(" ")], + ty: GraphqlNamedType { + name: GraphqlName { + value_token: GRAPHQL_NAME@25..30 "User" [] [Whitespace(" ")], + }, + }, + }, + directives: GraphqlDirectiveList [], + selection_set: GraphqlSelectionSet { + l_curly_token: L_CURLY@30..31 "{" [] [], + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@31..36 "id" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@36..43 "name" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@43..56 "profilePic" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: GraphqlArguments { + l_paren_token: L_PAREN@56..57 "(" [] [], + arguments: GraphqlArgumentList [ + GraphqlArgument { + name: GraphqlName { + value_token: GRAPHQL_NAME@57..61 "size" [] [], + }, + colon_token: COLON@61..63 ":" [] [Whitespace(" ")], + value: GraphqlIntValue { + graphql_int_literal_token: GRAPHQL_INT_LITERAL@63..65 "50" [] [], + }, + }, + ], + r_paren_token: R_PAREN@65..66 ")" [] [], + }, + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + ], + r_curly_token: R_CURLY@66..68 "}" [Newline("\n")] [], + }, + }, + GraphqlFragmentDefinition { + fragment_token: FRAGMENT_KW@68..79 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + name: GraphqlName { + value_token: GRAPHQL_NAME@79..92 "friendFields" [] [Whitespace(" ")], + }, + type_condition: GraphqlTypeCondition { + on_token: ON_KW@92..95 "on" [] [Whitespace(" ")], + ty: GraphqlNamedType { + name: GraphqlName { + value_token: GRAPHQL_NAME@95..100 "User" [] [Whitespace(" ")], + }, + }, + }, + directives: GraphqlDirectiveList [ + GraphqlDirective { + at_token: AT@100..101 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@101..112 "deprecated" [] [Whitespace(" ")], + }, + arguments: missing (optional), + }, + ], + selection_set: GraphqlSelectionSet { + l_curly_token: L_CURLY@112..113 "{" [] [], + selections: GraphqlSelectionList [ + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@113..118 "id" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@118..125 "name" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: missing (optional), + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + GraphqlField { + alias: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@125..138 "profilePic" [Newline("\n"), Whitespace(" ")] [], + }, + arguments: GraphqlArguments { + l_paren_token: L_PAREN@138..139 "(" [] [], + arguments: GraphqlArgumentList [ + GraphqlArgument { + name: GraphqlName { + value_token: GRAPHQL_NAME@139..143 "size" [] [], + }, + colon_token: COLON@143..145 ":" [] [Whitespace(" ")], + value: GraphqlIntValue { + graphql_int_literal_token: GRAPHQL_INT_LITERAL@145..147 "50" [] [], + }, + }, + ], + r_paren_token: R_PAREN@147..148 ")" [] [], + }, + directives: GraphqlDirectiveList [], + selection_set: missing (optional), + }, + ], + r_curly_token: R_CURLY@148..150 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@150..151 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: GRAPHQL_ROOT@0..151 + 0: (empty) + 1: GRAPHQL_DEFINITION_LIST@0..150 + 0: GRAPHQL_FRAGMENT_DEFINITION@0..68 + 0: FRAGMENT_KW@0..9 "fragment" [] [Whitespace(" ")] + 1: GRAPHQL_NAME@9..22 + 0: GRAPHQL_NAME@9..22 "friendFields" [] [Whitespace(" ")] + 2: GRAPHQL_TYPE_CONDITION@22..30 + 0: ON_KW@22..25 "on" [] [Whitespace(" ")] + 1: GRAPHQL_NAMED_TYPE@25..30 + 0: GRAPHQL_NAME@25..30 + 0: GRAPHQL_NAME@25..30 "User" [] [Whitespace(" ")] + 3: GRAPHQL_DIRECTIVE_LIST@30..30 + 4: GRAPHQL_SELECTION_SET@30..68 + 0: L_CURLY@30..31 "{" [] [] + 1: GRAPHQL_SELECTION_LIST@31..66 + 0: GRAPHQL_FIELD@31..36 + 0: (empty) + 1: GRAPHQL_NAME@31..36 + 0: GRAPHQL_NAME@31..36 "id" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@36..36 + 4: (empty) + 1: GRAPHQL_FIELD@36..43 + 0: (empty) + 1: GRAPHQL_NAME@36..43 + 0: GRAPHQL_NAME@36..43 "name" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@43..43 + 4: (empty) + 2: GRAPHQL_FIELD@43..66 + 0: (empty) + 1: GRAPHQL_NAME@43..56 + 0: GRAPHQL_NAME@43..56 "profilePic" [Newline("\n"), Whitespace(" ")] [] + 2: GRAPHQL_ARGUMENTS@56..66 + 0: L_PAREN@56..57 "(" [] [] + 1: GRAPHQL_ARGUMENT_LIST@57..65 + 0: GRAPHQL_ARGUMENT@57..65 + 0: GRAPHQL_NAME@57..61 + 0: GRAPHQL_NAME@57..61 "size" [] [] + 1: COLON@61..63 ":" [] [Whitespace(" ")] + 2: GRAPHQL_INT_VALUE@63..65 + 0: GRAPHQL_INT_LITERAL@63..65 "50" [] [] + 2: R_PAREN@65..66 ")" [] [] + 3: GRAPHQL_DIRECTIVE_LIST@66..66 + 4: (empty) + 2: R_CURLY@66..68 "}" [Newline("\n")] [] + 1: GRAPHQL_FRAGMENT_DEFINITION@68..150 + 0: FRAGMENT_KW@68..79 "fragment" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: GRAPHQL_NAME@79..92 + 0: GRAPHQL_NAME@79..92 "friendFields" [] [Whitespace(" ")] + 2: GRAPHQL_TYPE_CONDITION@92..100 + 0: ON_KW@92..95 "on" [] [Whitespace(" ")] + 1: GRAPHQL_NAMED_TYPE@95..100 + 0: GRAPHQL_NAME@95..100 + 0: GRAPHQL_NAME@95..100 "User" [] [Whitespace(" ")] + 3: GRAPHQL_DIRECTIVE_LIST@100..112 + 0: GRAPHQL_DIRECTIVE@100..112 + 0: AT@100..101 "@" [] [] + 1: GRAPHQL_NAME@101..112 + 0: GRAPHQL_NAME@101..112 "deprecated" [] [Whitespace(" ")] + 2: (empty) + 4: GRAPHQL_SELECTION_SET@112..150 + 0: L_CURLY@112..113 "{" [] [] + 1: GRAPHQL_SELECTION_LIST@113..148 + 0: GRAPHQL_FIELD@113..118 + 0: (empty) + 1: GRAPHQL_NAME@113..118 + 0: GRAPHQL_NAME@113..118 "id" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@118..118 + 4: (empty) + 1: GRAPHQL_FIELD@118..125 + 0: (empty) + 1: GRAPHQL_NAME@118..125 + 0: GRAPHQL_NAME@118..125 "name" [Newline("\n"), Whitespace(" ")] [] + 2: (empty) + 3: GRAPHQL_DIRECTIVE_LIST@125..125 + 4: (empty) + 2: GRAPHQL_FIELD@125..148 + 0: (empty) + 1: GRAPHQL_NAME@125..138 + 0: GRAPHQL_NAME@125..138 "profilePic" [Newline("\n"), Whitespace(" ")] [] + 2: GRAPHQL_ARGUMENTS@138..148 + 0: L_PAREN@138..139 "(" [] [] + 1: GRAPHQL_ARGUMENT_LIST@139..147 + 0: GRAPHQL_ARGUMENT@139..147 + 0: GRAPHQL_NAME@139..143 + 0: GRAPHQL_NAME@139..143 "size" [] [] + 1: COLON@143..145 ":" [] [Whitespace(" ")] + 2: GRAPHQL_INT_VALUE@145..147 + 0: GRAPHQL_INT_LITERAL@145..147 "50" [] [] + 2: R_PAREN@147..148 ")" [] [] + 3: GRAPHQL_DIRECTIVE_LIST@148..148 + 4: (empty) + 2: R_CURLY@148..150 "}" [Newline("\n")] [] + 2: EOF@150..151 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_graphql_parser/tests/spec_tests.rs b/crates/biome_graphql_parser/tests/spec_tests.rs index 53b31f22ca24..e8e4cca8b657 100644 --- a/crates/biome_graphql_parser/tests/spec_tests.rs +++ b/crates/biome_graphql_parser/tests/spec_tests.rs @@ -4,10 +4,10 @@ mod spec_test; mod ok { //! Tests that are valid GraphQL - tests_macros::gen_tests! {"tests/graphql_test_suite/ok/*.graphql", crate::spec_test::run, "ok"} + tests_macros::gen_tests! {"tests/graphql_test_suite/ok/**/*.graphql", crate::spec_test::run, "ok"} } mod err { //! Tests that must fail because they are not valid GraphQL - tests_macros::gen_tests! {"tests/graphql_test_suite/err/*.graphql", crate::spec_test::run, "error"} + tests_macros::gen_tests! {"tests/graphql_test_suite/err/**/*.graphql", crate::spec_test::run, "error"} }