From 9bb61856e51c28afefa68cfd135f1b17e018e5ea Mon Sep 17 00:00:00 2001 From: vohoanglong0107 Date: Wed, 8 May 2024 23:56:55 +0000 Subject: [PATCH 1/2] feat(biome_graphql_parser): parse directive definition --- .../src/parser/definitions/directive.rs | 140 +++++ .../src/parser/definitions/field.rs | 4 +- .../src/parser/definitions/mod.rs | 7 +- .../src/parser/parse_error.rs | 28 + .../definitions/directive_definition.graphql | 20 + .../directive_definition.graphql.snap | 493 ++++++++++++++++++ .../definitions/directive_definition.graphql | 10 + .../directive_definition.graphql.snap | 230 ++++++++ 8 files changed, 928 insertions(+), 4 deletions(-) create mode 100644 crates/biome_graphql_parser/src/parser/definitions/directive.rs create mode 100644 crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql create mode 100644 crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap create mode 100644 crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql create mode 100644 crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql.snap diff --git a/crates/biome_graphql_parser/src/parser/definitions/directive.rs b/crates/biome_graphql_parser/src/parser/definitions/directive.rs new file mode 100644 index 000000000000..57bd1a9a7531 --- /dev/null +++ b/crates/biome_graphql_parser/src/parser/definitions/directive.rs @@ -0,0 +1,140 @@ +use crate::parser::{ + parse_description, + parse_error::{expected_directive_location, expected_name}, + parse_name, + value::is_at_string, + GraphqlParser, +}; +use biome_graphql_syntax::{ + GraphqlSyntaxKind::{self, *}, + T, +}; +use biome_parser::prelude::TokenSource; +use biome_parser::{ + parse_lists::ParseSeparatedList, parse_recovery::ParseRecovery, parsed_syntax::ParsedSyntax, + prelude::ParsedSyntax::*, token_set, Parser, TokenSet, +}; + +use super::{field::parse_arguments_definition, is_at_definition}; + +const DIRECTIVE_LOCATION_SET: TokenSet = token_set!( + T![UPPER_QUERY], + T![UPPER_MUTATION], + T![UPPER_SUBSCRIPTION], + T![UPPER_FIELD], + T![FRAGMENT_DEFINITION], + T![FRAGMENT_SPREAD], + T![INLINE_FRAGMENT], + T![VARIABLE_DEFINITION], + T![UPPER_SCHEMA], + T![UPPER_SCALAR], + T![UPPER_OBJECT], + T![FIELD_DEFINITION], + T![ARGUMENT_DEFINITION], + T![UPPER_INTERFACE], + T![UPPER_UNION], + T![UPPER_ENUM], + T![ENUM_VALUE], + T![INPUT_OBJECT], + T![INPUT_FIELD_DEFINITION] +); + +#[inline] +pub(crate) fn parse_directive_definition(p: &mut GraphqlParser) -> ParsedSyntax { + if !is_at_directive_definition(p) { + return Absent; + } + let m = p.start(); + + // description is optional + parse_description(p).ok(); + + p.bump(T![directive]); + p.expect(T![@]); + parse_name(p).or_add_diagnostic(p, expected_name); + + // arguments are optional + parse_arguments_definition(p).ok(); + + // repeatable is optional + p.eat(T![repeatable]); + p.expect(T![on]); + + // | is optional + p.eat(T![|]); + + let position = p.source().position(); + DirectiveLocationList.parse_list(p); + + // has not progressed, meaning no directive locations were parsed + if position == p.source().position() { + p.error(expected_directive_location(p, p.cur_range())); + } + + Present(m.complete(p, GRAPHQL_DIRECTIVE_DEFINITION)) +} + +#[derive(Default)] +struct DirectiveLocationList; + +impl ParseSeparatedList for DirectiveLocationList { + type Kind = GraphqlSyntaxKind; + type Parser<'source> = GraphqlParser<'source>; + + const LIST_KIND: Self::Kind = GRAPHQL_DIRECTIVE_LOCATION_LIST; + + fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { + parse_directive_location(p) + } + + fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool { + is_at_definition(p) + } + + fn recover( + &mut self, + p: &mut Self::Parser<'_>, + parsed_element: ParsedSyntax, + ) -> biome_parser::parse_recovery::RecoveryResult { + parsed_element.or_recover( + p, + &DirectiveLocationListParseRecovery, + expected_directive_location, + ) + } + + fn separating_element_kind(&mut self) -> Self::Kind { + T![|] + } + + fn allow_trailing_separating_element(&self) -> bool { + false + } +} + +struct DirectiveLocationListParseRecovery; + +impl ParseRecovery for DirectiveLocationListParseRecovery { + type Kind = GraphqlSyntaxKind; + type Parser<'source> = GraphqlParser<'source>; + const RECOVERED_KIND: Self::Kind = GRAPHQL_BOGUS; + + fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool { + p.at_ts(DIRECTIVE_LOCATION_SET) || is_at_definition(p) + } +} + +#[inline] +fn parse_directive_location(p: &mut GraphqlParser) -> ParsedSyntax { + if !p.at_ts(DIRECTIVE_LOCATION_SET) { + return Absent; + } + let m = p.start(); + p.bump_ts(DIRECTIVE_LOCATION_SET); + Present(m.complete(p, GRAPHQL_DIRECTIVE_LOCATION)) +} + +#[inline] +pub(crate) fn is_at_directive_definition(p: &mut GraphqlParser) -> bool { + p.at(T![directive]) || (is_at_string(p) && p.nth_at(1, T![directive])) +} diff --git a/crates/biome_graphql_parser/src/parser/definitions/field.rs b/crates/biome_graphql_parser/src/parser/definitions/field.rs index 4edb84d9fc43..30ab2abb9509 100644 --- a/crates/biome_graphql_parser/src/parser/definitions/field.rs +++ b/crates/biome_graphql_parser/src/parser/definitions/field.rs @@ -97,7 +97,7 @@ fn parse_field_definition(p: &mut GraphqlParser) -> ParsedSyntax { } #[inline] -fn parse_arguments_definition(p: &mut GraphqlParser) -> ParsedSyntax { +pub(super) fn parse_arguments_definition(p: &mut GraphqlParser) -> ParsedSyntax { if !is_at_arguments_definition(p) { return Absent; } @@ -215,7 +215,7 @@ pub(super) fn is_at_input_value_definition(p: &mut GraphqlParser<'_>) -> bool { /// In this case, the opening parenthesis is missing, the name token of an input value definition /// is also missing. It would be to complex to disambiguate input value definitions from field. #[inline] -fn is_at_arguments_definition(p: &mut GraphqlParser<'_>) -> bool { +pub(super) fn is_at_arguments_definition(p: &mut GraphqlParser<'_>) -> bool { p.at(T!['(']) } diff --git a/crates/biome_graphql_parser/src/parser/definitions/mod.rs b/crates/biome_graphql_parser/src/parser/definitions/mod.rs index 8d8748c55a63..5ad3bede204e 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 directive; mod r#enum; mod field; mod fragment; @@ -17,6 +18,7 @@ use biome_parser::{ }; use self::{ + directive::{is_at_directive_definition, parse_directive_definition}, fragment::{is_at_fragment_definition, parse_fragment_definition}, input_object::{is_at_input_object_type_definition, parse_input_object_type_definition}, interface::{is_at_interface_type_definition, parse_interface_type_definition}, @@ -69,7 +71,6 @@ impl ParseNodeList for DefinitionList { #[inline] fn parse_definition(p: &mut GraphqlParser) -> ParsedSyntax { - // TODO: add directive definition if is_at_operation(p) { parse_operation_definition(p) } else if is_at_fragment_definition(p) { @@ -88,6 +89,8 @@ fn parse_definition(p: &mut GraphqlParser) -> ParsedSyntax { parse_enum_type_definition(p) } else if is_at_input_object_type_definition(p) { parse_input_object_type_definition(p) + } else if is_at_directive_definition(p) { + parse_directive_definition(p) } else { Absent } @@ -95,7 +98,6 @@ fn parse_definition(p: &mut GraphqlParser) -> ParsedSyntax { #[inline] fn is_at_definition(p: &mut GraphqlParser<'_>) -> bool { - // TODO: add directive definition is_at_operation(p) || is_at_fragment_definition(p) || is_at_schema_definition(p) @@ -105,4 +107,5 @@ fn is_at_definition(p: &mut GraphqlParser<'_>) -> bool { || is_at_union_type_definition(p) || is_at_enum_type_definition(p) || is_at_input_object_type_definition(p) + || is_at_directive_definition(p) } diff --git a/crates/biome_graphql_parser/src/parser/parse_error.rs b/crates/biome_graphql_parser/src/parser/parse_error.rs index e15ed09977c1..7647b3c0e96c 100644 --- a/crates/biome_graphql_parser/src/parser/parse_error.rs +++ b/crates/biome_graphql_parser/src/parser/parse_error.rs @@ -60,3 +60,31 @@ pub(crate) fn expected_root_operation_type_definition( pub(crate) fn expected_operation_type(p: &GraphqlParser, range: TextRange) -> ParseDiagnostic { expected_any(&["query", "mutation", "subscription"], range, p) } + +pub(crate) fn expected_directive_location(p: &GraphqlParser, range: TextRange) -> ParseDiagnostic { + expected_any( + &[ + "QUERY", + "MUTATION", + "SUBSCRIPTION", + "FIELD", + "FRAGMENT_DEFINITION", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT", + "VARIABLE_DEFINITION", + "SCHEMA", + "SCALAR", + "OBJECT", + "FIELD_DEFINITION", + "ARGUMENT_DEFINITION", + "INTERFACE", + "UNION", + "ENUM", + "ENUM_VALUE", + "INPUT_OBJECT", + "INPUT_FIELD_DEFINITION", + ], + range, + p, + ) +} diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql new file mode 100644 index 000000000000..03fd46986ec0 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql @@ -0,0 +1,20 @@ +directive @example on | + +directive @ on | ARGUMENT_DEFINITION + +directive example on | ARGUMENT_DEFINITION +directive example ARGUMENT_DEFINITION + +directive @example on + | FIELD + | FRAGMENT_SPREAD + | + +directive @delegateField(: !) repeatable on OBJECT | INTERFACE + +directve @example on + +directive @example on + | # + | 123 + | name diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap new file mode 100644 index 000000000000..234a90d89645 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap @@ -0,0 +1,493 @@ +--- +source: crates/biome_graphql_parser/tests/spec_test.rs +expression: snapshot +--- +## Input +```graphql +directive @example on | + +directive @ on | ARGUMENT_DEFINITION + +directive example on | ARGUMENT_DEFINITION +directive example ARGUMENT_DEFINITION + +directive @example on + | FIELD + | FRAGMENT_SPREAD + | + +directive @delegateField(: !) repeatable on OBJECT | INTERFACE + +directve @example on + +directive @example on + | # + | 123 + | name + +``` + +## AST + +``` +GraphqlRoot { + bom_token: missing (optional), + definitions: GraphqlDefinitionList [ + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@0..10 "directive" [] [Whitespace(" ")], + at_token: AT@10..11 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@11..19 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@19..22 "on" [] [Whitespace(" ")], + bitwise_or_token: PIPE@22..23 "|" [] [], + locations: GraphqlDirectiveLocationList [], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@23..35 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + at_token: AT@35..37 "@" [] [Whitespace(" ")], + name: missing (required), + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@37..40 "on" [] [Whitespace(" ")], + bitwise_or_token: PIPE@40..42 "|" [] [Whitespace(" ")], + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: ARGUMENT_DEFINITION_KW@42..61 "ARGUMENT_DEFINITION" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@61..73 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + at_token: missing (required), + name: GraphqlName { + value_token: GRAPHQL_NAME@73..81 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@81..84 "on" [] [Whitespace(" ")], + bitwise_or_token: PIPE@84..86 "|" [] [Whitespace(" ")], + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: ARGUMENT_DEFINITION_KW@86..105 "ARGUMENT_DEFINITION" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@105..116 "directive" [Newline("\n")] [Whitespace(" ")], + at_token: missing (required), + name: GraphqlName { + value_token: GRAPHQL_NAME@116..124 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: missing (required), + bitwise_or_token: missing (optional), + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: ARGUMENT_DEFINITION_KW@124..143 "ARGUMENT_DEFINITION" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@143..155 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + at_token: AT@155..156 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@156..164 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@164..166 "on" [] [], + bitwise_or_token: PIPE@166..171 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: UPPER_FIELD_KW@171..176 "FIELD" [] [], + }, + PIPE@176..181 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: FRAGMENT_SPREAD_KW@181..196 "FRAGMENT_SPREAD" [] [], + }, + PIPE@196..200 "|" [Newline("\n"), Whitespace(" ")] [], + missing element, + ], + }, + GraphqlBogusDefinition { + items: [ + DIRECTIVE_KW@200..212 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + AT@212..213 "@" [] [], + GraphqlName { + value_token: GRAPHQL_NAME@213..226 "delegateField" [] [], + }, + GraphqlArgumentsDefinition { + l_paren_token: L_PAREN@226..227 "(" [] [], + arguments: GraphqlArgumentDefinitionList [ + GraphqlInputValueDefinition { + description: missing (optional), + name: missing (required), + colon_token: COLON@227..229 ":" [] [Whitespace(" ")], + ty: GraphqlNonNullType { + base: missing (required), + excl_token: BANG@229..230 "!" [] [], + }, + default: missing (optional), + directives: GraphqlDirectiveList [], + }, + ], + r_paren_token: R_PAREN@230..232 ")" [] [Whitespace(" ")], + }, + REPEATABLE_KW@232..243 "repeatable" [] [Whitespace(" ")], + ON_KW@243..246 "on" [] [Whitespace(" ")], + GraphqlBogus { + items: [ + GraphqlDirectiveLocation { + value_token: UPPER_OBJECT_KW@246..253 "OBJECT" [] [Whitespace(" ")], + }, + PIPE@253..255 "|" [] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: UPPER_INTERFACE_KW@255..264 "INTERFACE" [] [], + }, + GraphqlBogus { + items: [ + GRAPHQL_NAME@264..275 "directve" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + AT@275..276 "@" [] [], + GRAPHQL_NAME@276..284 "example" [] [Whitespace(" ")], + ON_KW@284..286 "on" [] [], + ], + }, + ], + }, + ], + }, + GraphqlBogusDefinition { + items: [ + DIRECTIVE_KW@286..298 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + AT@298..299 "@" [] [], + GraphqlName { + value_token: GRAPHQL_NAME@299..307 "example" [] [Whitespace(" ")], + }, + ON_KW@307..309 "on" [] [], + PIPE@309..315 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" "), Comments("#")], + GraphqlBogus { + items: [ + PIPE@315..320 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + GraphqlBogus { + items: [ + GRAPHQL_INT_LITERAL@320..323 "123" [] [], + PIPE@323..328 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + GRAPHQL_NAME@328..332 "name" [] [], + ], + }, + ], + }, + ], + }, + ], + eof_token: EOF@332..333 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: GRAPHQL_ROOT@0..333 + 0: (empty) + 1: GRAPHQL_DEFINITION_LIST@0..332 + 0: GRAPHQL_DIRECTIVE_DEFINITION@0..23 + 0: (empty) + 1: DIRECTIVE_KW@0..10 "directive" [] [Whitespace(" ")] + 2: AT@10..11 "@" [] [] + 3: GRAPHQL_NAME@11..19 + 0: GRAPHQL_NAME@11..19 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@19..22 "on" [] [Whitespace(" ")] + 7: PIPE@22..23 "|" [] [] + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@23..23 + 1: GRAPHQL_DIRECTIVE_DEFINITION@23..61 + 0: (empty) + 1: DIRECTIVE_KW@23..35 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: AT@35..37 "@" [] [Whitespace(" ")] + 3: (empty) + 4: (empty) + 5: (empty) + 6: ON_KW@37..40 "on" [] [Whitespace(" ")] + 7: PIPE@40..42 "|" [] [Whitespace(" ")] + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@42..61 + 0: GRAPHQL_DIRECTIVE_LOCATION@42..61 + 0: ARGUMENT_DEFINITION_KW@42..61 "ARGUMENT_DEFINITION" [] [] + 2: GRAPHQL_DIRECTIVE_DEFINITION@61..105 + 0: (empty) + 1: DIRECTIVE_KW@61..73 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: (empty) + 3: GRAPHQL_NAME@73..81 + 0: GRAPHQL_NAME@73..81 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@81..84 "on" [] [Whitespace(" ")] + 7: PIPE@84..86 "|" [] [Whitespace(" ")] + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@86..105 + 0: GRAPHQL_DIRECTIVE_LOCATION@86..105 + 0: ARGUMENT_DEFINITION_KW@86..105 "ARGUMENT_DEFINITION" [] [] + 3: GRAPHQL_DIRECTIVE_DEFINITION@105..143 + 0: (empty) + 1: DIRECTIVE_KW@105..116 "directive" [Newline("\n")] [Whitespace(" ")] + 2: (empty) + 3: GRAPHQL_NAME@116..124 + 0: GRAPHQL_NAME@116..124 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: (empty) + 7: (empty) + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@124..143 + 0: GRAPHQL_DIRECTIVE_LOCATION@124..143 + 0: ARGUMENT_DEFINITION_KW@124..143 "ARGUMENT_DEFINITION" [] [] + 4: GRAPHQL_DIRECTIVE_DEFINITION@143..200 + 0: (empty) + 1: DIRECTIVE_KW@143..155 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: AT@155..156 "@" [] [] + 3: GRAPHQL_NAME@156..164 + 0: GRAPHQL_NAME@156..164 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@164..166 "on" [] [] + 7: PIPE@166..171 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@171..200 + 0: GRAPHQL_DIRECTIVE_LOCATION@171..176 + 0: UPPER_FIELD_KW@171..176 "FIELD" [] [] + 1: PIPE@176..181 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 2: GRAPHQL_DIRECTIVE_LOCATION@181..196 + 0: FRAGMENT_SPREAD_KW@181..196 "FRAGMENT_SPREAD" [] [] + 3: PIPE@196..200 "|" [Newline("\n"), Whitespace(" ")] [] + 4: (empty) + 5: GRAPHQL_BOGUS_DEFINITION@200..286 + 0: DIRECTIVE_KW@200..212 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: AT@212..213 "@" [] [] + 2: GRAPHQL_NAME@213..226 + 0: GRAPHQL_NAME@213..226 "delegateField" [] [] + 3: GRAPHQL_ARGUMENTS_DEFINITION@226..232 + 0: L_PAREN@226..227 "(" [] [] + 1: GRAPHQL_ARGUMENT_DEFINITION_LIST@227..230 + 0: GRAPHQL_INPUT_VALUE_DEFINITION@227..230 + 0: (empty) + 1: (empty) + 2: COLON@227..229 ":" [] [Whitespace(" ")] + 3: GRAPHQL_NON_NULL_TYPE@229..230 + 0: (empty) + 1: BANG@229..230 "!" [] [] + 4: (empty) + 5: GRAPHQL_DIRECTIVE_LIST@230..230 + 2: R_PAREN@230..232 ")" [] [Whitespace(" ")] + 4: REPEATABLE_KW@232..243 "repeatable" [] [Whitespace(" ")] + 5: ON_KW@243..246 "on" [] [Whitespace(" ")] + 6: GRAPHQL_BOGUS@246..286 + 0: GRAPHQL_DIRECTIVE_LOCATION@246..253 + 0: UPPER_OBJECT_KW@246..253 "OBJECT" [] [Whitespace(" ")] + 1: PIPE@253..255 "|" [] [Whitespace(" ")] + 2: GRAPHQL_DIRECTIVE_LOCATION@255..264 + 0: UPPER_INTERFACE_KW@255..264 "INTERFACE" [] [] + 3: GRAPHQL_BOGUS@264..286 + 0: GRAPHQL_NAME@264..275 "directve" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: AT@275..276 "@" [] [] + 2: GRAPHQL_NAME@276..284 "example" [] [Whitespace(" ")] + 3: ON_KW@284..286 "on" [] [] + 6: GRAPHQL_BOGUS_DEFINITION@286..332 + 0: DIRECTIVE_KW@286..298 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: AT@298..299 "@" [] [] + 2: GRAPHQL_NAME@299..307 + 0: GRAPHQL_NAME@299..307 "example" [] [Whitespace(" ")] + 3: ON_KW@307..309 "on" [] [] + 4: PIPE@309..315 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" "), Comments("#")] + 5: GRAPHQL_BOGUS@315..332 + 0: PIPE@315..320 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 1: GRAPHQL_BOGUS@320..332 + 0: GRAPHQL_INT_LITERAL@320..323 "123" [] [] + 1: PIPE@323..328 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 2: GRAPHQL_NAME@328..332 "name" [] [] + 2: EOF@332..333 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +directive_definition.graphql:3:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found 'directive'. + + 1 │ directive @example on | + 2 │ + > 3 │ directive @ on | ARGUMENT_DEFINITION + │ ^^^^^^^^^ + 4 │ + 5 │ directive example on | ARGUMENT_DEFINITION + + i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. + + 1 │ directive @example on | + 2 │ + > 3 │ directive @ on | ARGUMENT_DEFINITION + │ ^^^^^^^^^ + 4 │ + 5 │ directive example on | ARGUMENT_DEFINITION + +directive_definition.graphql:3:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a name but instead found 'on'. + + 1 │ directive @example on | + 2 │ + > 3 │ directive @ on | ARGUMENT_DEFINITION + │ ^^ + 4 │ + 5 │ directive example on | ARGUMENT_DEFINITION + + i Expected a name here. + + 1 │ directive @example on | + 2 │ + > 3 │ directive @ on | ARGUMENT_DEFINITION + │ ^^ + 4 │ + 5 │ directive example on | ARGUMENT_DEFINITION + +directive_definition.graphql:5:11 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `@` but instead found `example` + + 3 │ directive @ on | ARGUMENT_DEFINITION + 4 │ + > 5 │ directive example on | ARGUMENT_DEFINITION + │ ^^^^^^^ + 6 │ directive example ARGUMENT_DEFINITION + 7 │ + + i Remove example + +directive_definition.graphql:6:11 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `@` but instead found `example` + + 5 │ directive example on | ARGUMENT_DEFINITION + > 6 │ directive example ARGUMENT_DEFINITION + │ ^^^^^^^ + 7 │ + 8 │ directive @example on + + i Remove example + +directive_definition.graphql:6:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `on` but instead found `ARGUMENT_DEFINITION` + + 5 │ directive example on | ARGUMENT_DEFINITION + > 6 │ directive example ARGUMENT_DEFINITION + │ ^^^^^^^^^^^^^^^^^^^ + 7 │ + 8 │ directive @example on + + i Remove ARGUMENT_DEFINITION + +directive_definition.graphql:13:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found 'directive'. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^^^^^^^^^ + 14 │ + 15 │ directve @example on + + i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^^^^^^^^^ + 14 │ + 15 │ directve @example on + +directive_definition.graphql:13:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a name but instead found ':'. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^ + 14 │ + 15 │ directve @example on + + i Expected a name here. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^ + 14 │ + 15 │ directve @example on + +directive_definition.graphql:13:29 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a named type, or a list type but instead found ')'. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^ + 14 │ + 15 │ directve @example on + + i Expected a named type, or a list type here. + + 11 │ | + 12 │ + > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + │ ^ + 14 │ + 15 │ directve @example on + +directive_definition.graphql:15:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `|` but instead found `directve` + + 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE + 14 │ + > 15 │ directve @example on + │ ^^^^^^^^ + 16 │ + 17 │ directive @example on + + i Remove directve + +directive_definition.graphql:19:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found '123 + | name'. + + 17 │ directive @example on + 18 │ | # + > 19 │ | 123 + │ ^^^ + > 20 │ | name + │ ^^^^^^ + 21 │ + + i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. + + 17 │ directive @example on + 18 │ | # + > 19 │ | 123 + │ ^^^ + > 20 │ | name + │ ^^^^^^ + 21 │ + +``` diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql new file mode 100644 index 000000000000..50d510e5db32 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql @@ -0,0 +1,10 @@ +directive @example on FIELD + +directive @example on FIELD_DEFINITION | ARGUMENT_DEFINITION + +directive @example on + | FIELD + | FRAGMENT_SPREAD + | INLINE_FRAGMENT + +"deprecated" directive @delegateField(name: String!) repeatable on OBJECT | INTERFACE diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql.snap b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql.snap new file mode 100644 index 000000000000..9e4ddbf3b071 --- /dev/null +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/ok/definitions/directive_definition.graphql.snap @@ -0,0 +1,230 @@ +--- +source: crates/biome_graphql_parser/tests/spec_test.rs +expression: snapshot +--- +## Input +```graphql +directive @example on FIELD + +directive @example on FIELD_DEFINITION | ARGUMENT_DEFINITION + +directive @example on + | FIELD + | FRAGMENT_SPREAD + | INLINE_FRAGMENT + +"deprecated" directive @delegateField(name: String!) repeatable on OBJECT | INTERFACE + +``` + +## AST + +``` +GraphqlRoot { + bom_token: missing (optional), + definitions: GraphqlDefinitionList [ + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@0..10 "directive" [] [Whitespace(" ")], + at_token: AT@10..11 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@11..19 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@19..22 "on" [] [Whitespace(" ")], + bitwise_or_token: missing (optional), + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: UPPER_FIELD_KW@22..27 "FIELD" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@27..39 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + at_token: AT@39..40 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@40..48 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@48..51 "on" [] [Whitespace(" ")], + bitwise_or_token: missing (optional), + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: FIELD_DEFINITION_KW@51..68 "FIELD_DEFINITION" [] [Whitespace(" ")], + }, + PIPE@68..70 "|" [] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: ARGUMENT_DEFINITION_KW@70..89 "ARGUMENT_DEFINITION" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: missing (optional), + directive_token: DIRECTIVE_KW@89..101 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + at_token: AT@101..102 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@102..110 "example" [] [Whitespace(" ")], + }, + arguments: missing (optional), + repeatable_token: missing (optional), + on_token: ON_KW@110..112 "on" [] [], + bitwise_or_token: PIPE@112..117 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: UPPER_FIELD_KW@117..122 "FIELD" [] [], + }, + PIPE@122..127 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: FRAGMENT_SPREAD_KW@127..142 "FRAGMENT_SPREAD" [] [], + }, + PIPE@142..147 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: INLINE_FRAGMENT_KW@147..162 "INLINE_FRAGMENT" [] [], + }, + ], + }, + GraphqlDirectiveDefinition { + description: GraphqlDescription { + graphql_string_value: GraphqlStringValue { + graphql_string_literal_token: GRAPHQL_STRING_LITERAL@162..177 "\"deprecated\"" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + }, + }, + directive_token: DIRECTIVE_KW@177..187 "directive" [] [Whitespace(" ")], + at_token: AT@187..188 "@" [] [], + name: GraphqlName { + value_token: GRAPHQL_NAME@188..201 "delegateField" [] [], + }, + arguments: GraphqlArgumentsDefinition { + l_paren_token: L_PAREN@201..202 "(" [] [], + arguments: GraphqlArgumentDefinitionList [ + GraphqlInputValueDefinition { + description: missing (optional), + name: GraphqlName { + value_token: GRAPHQL_NAME@202..206 "name" [] [], + }, + colon_token: COLON@206..208 ":" [] [Whitespace(" ")], + ty: GraphqlNonNullType { + base: GraphqlNamedType { + name: GraphqlName { + value_token: GRAPHQL_NAME@208..214 "String" [] [], + }, + }, + excl_token: BANG@214..215 "!" [] [], + }, + default: missing (optional), + directives: GraphqlDirectiveList [], + }, + ], + r_paren_token: R_PAREN@215..217 ")" [] [Whitespace(" ")], + }, + repeatable_token: REPEATABLE_KW@217..228 "repeatable" [] [Whitespace(" ")], + on_token: ON_KW@228..231 "on" [] [Whitespace(" ")], + bitwise_or_token: missing (optional), + locations: GraphqlDirectiveLocationList [ + GraphqlDirectiveLocation { + value_token: UPPER_OBJECT_KW@231..238 "OBJECT" [] [Whitespace(" ")], + }, + PIPE@238..240 "|" [] [Whitespace(" ")], + GraphqlDirectiveLocation { + value_token: UPPER_INTERFACE_KW@240..249 "INTERFACE" [] [], + }, + ], + }, + ], + eof_token: EOF@249..250 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: GRAPHQL_ROOT@0..250 + 0: (empty) + 1: GRAPHQL_DEFINITION_LIST@0..249 + 0: GRAPHQL_DIRECTIVE_DEFINITION@0..27 + 0: (empty) + 1: DIRECTIVE_KW@0..10 "directive" [] [Whitespace(" ")] + 2: AT@10..11 "@" [] [] + 3: GRAPHQL_NAME@11..19 + 0: GRAPHQL_NAME@11..19 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@19..22 "on" [] [Whitespace(" ")] + 7: (empty) + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@22..27 + 0: GRAPHQL_DIRECTIVE_LOCATION@22..27 + 0: UPPER_FIELD_KW@22..27 "FIELD" [] [] + 1: GRAPHQL_DIRECTIVE_DEFINITION@27..89 + 0: (empty) + 1: DIRECTIVE_KW@27..39 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: AT@39..40 "@" [] [] + 3: GRAPHQL_NAME@40..48 + 0: GRAPHQL_NAME@40..48 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@48..51 "on" [] [Whitespace(" ")] + 7: (empty) + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@51..89 + 0: GRAPHQL_DIRECTIVE_LOCATION@51..68 + 0: FIELD_DEFINITION_KW@51..68 "FIELD_DEFINITION" [] [Whitespace(" ")] + 1: PIPE@68..70 "|" [] [Whitespace(" ")] + 2: GRAPHQL_DIRECTIVE_LOCATION@70..89 + 0: ARGUMENT_DEFINITION_KW@70..89 "ARGUMENT_DEFINITION" [] [] + 2: GRAPHQL_DIRECTIVE_DEFINITION@89..162 + 0: (empty) + 1: DIRECTIVE_KW@89..101 "directive" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: AT@101..102 "@" [] [] + 3: GRAPHQL_NAME@102..110 + 0: GRAPHQL_NAME@102..110 "example" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: ON_KW@110..112 "on" [] [] + 7: PIPE@112..117 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@117..162 + 0: GRAPHQL_DIRECTIVE_LOCATION@117..122 + 0: UPPER_FIELD_KW@117..122 "FIELD" [] [] + 1: PIPE@122..127 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 2: GRAPHQL_DIRECTIVE_LOCATION@127..142 + 0: FRAGMENT_SPREAD_KW@127..142 "FRAGMENT_SPREAD" [] [] + 3: PIPE@142..147 "|" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 4: GRAPHQL_DIRECTIVE_LOCATION@147..162 + 0: INLINE_FRAGMENT_KW@147..162 "INLINE_FRAGMENT" [] [] + 3: GRAPHQL_DIRECTIVE_DEFINITION@162..249 + 0: GRAPHQL_DESCRIPTION@162..177 + 0: GRAPHQL_STRING_VALUE@162..177 + 0: GRAPHQL_STRING_LITERAL@162..177 "\"deprecated\"" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: DIRECTIVE_KW@177..187 "directive" [] [Whitespace(" ")] + 2: AT@187..188 "@" [] [] + 3: GRAPHQL_NAME@188..201 + 0: GRAPHQL_NAME@188..201 "delegateField" [] [] + 4: GRAPHQL_ARGUMENTS_DEFINITION@201..217 + 0: L_PAREN@201..202 "(" [] [] + 1: GRAPHQL_ARGUMENT_DEFINITION_LIST@202..215 + 0: GRAPHQL_INPUT_VALUE_DEFINITION@202..215 + 0: (empty) + 1: GRAPHQL_NAME@202..206 + 0: GRAPHQL_NAME@202..206 "name" [] [] + 2: COLON@206..208 ":" [] [Whitespace(" ")] + 3: GRAPHQL_NON_NULL_TYPE@208..215 + 0: GRAPHQL_NAMED_TYPE@208..214 + 0: GRAPHQL_NAME@208..214 + 0: GRAPHQL_NAME@208..214 "String" [] [] + 1: BANG@214..215 "!" [] [] + 4: (empty) + 5: GRAPHQL_DIRECTIVE_LIST@215..215 + 2: R_PAREN@215..217 ")" [] [Whitespace(" ")] + 5: REPEATABLE_KW@217..228 "repeatable" [] [Whitespace(" ")] + 6: ON_KW@228..231 "on" [] [Whitespace(" ")] + 7: (empty) + 8: GRAPHQL_DIRECTIVE_LOCATION_LIST@231..249 + 0: GRAPHQL_DIRECTIVE_LOCATION@231..238 + 0: UPPER_OBJECT_KW@231..238 "OBJECT" [] [Whitespace(" ")] + 1: PIPE@238..240 "|" [] [Whitespace(" ")] + 2: GRAPHQL_DIRECTIVE_LOCATION@240..249 + 0: UPPER_INTERFACE_KW@240..249 "INTERFACE" [] [] + 2: EOF@249..250 "" [Newline("\n")] [] + +``` From 79b80783478c0e54268b1614ec7ac0d6e96b4ad5 Mon Sep 17 00:00:00 2001 From: vohoanglong0107 Date: Thu, 9 May 2024 07:22:44 +0000 Subject: [PATCH 2/2] fix(biome_graphql_parser): better diagnostic for directive location --- .../src/parser/parse_error.rs | 55 ++++++----- .../directive_definition.graphql.snap | 95 +++++++++++++------ 2 files changed, 95 insertions(+), 55 deletions(-) diff --git a/crates/biome_graphql_parser/src/parser/parse_error.rs b/crates/biome_graphql_parser/src/parser/parse_error.rs index 7647b3c0e96c..cdc3240901e7 100644 --- a/crates/biome_graphql_parser/src/parser/parse_error.rs +++ b/crates/biome_graphql_parser/src/parser/parse_error.rs @@ -1,5 +1,8 @@ use crate::parser::GraphqlParser; -use biome_parser::diagnostic::{expected_any, expected_node, ParseDiagnostic}; +use biome_parser::{ + diagnostic::{expected_any, expected_node, ParseDiagnostic}, + Parser, +}; use biome_rowan::TextRange; pub(crate) fn expected_any_definition(p: &GraphqlParser, range: TextRange) -> ParseDiagnostic { @@ -62,29 +65,29 @@ pub(crate) fn expected_operation_type(p: &GraphqlParser, range: TextRange) -> Pa } pub(crate) fn expected_directive_location(p: &GraphqlParser, range: TextRange) -> ParseDiagnostic { - expected_any( - &[ - "QUERY", - "MUTATION", - "SUBSCRIPTION", - "FIELD", - "FRAGMENT_DEFINITION", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT", - "VARIABLE_DEFINITION", - "SCHEMA", - "SCALAR", - "OBJECT", - "FIELD_DEFINITION", - "ARGUMENT_DEFINITION", - "INTERFACE", - "UNION", - "ENUM", - "ENUM_VALUE", - "INPUT_OBJECT", - "INPUT_FIELD_DEFINITION", - ], - range, - p, - ) + p.err_builder("Expected a valid directive location", range) + .with_alternatives( + "Must be one of:", + &[ + "QUERY", + "MUTATION", + "SUBSCRIPTION", + "FIELD", + "FRAGMENT_DEFINITION", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT", + "VARIABLE_DEFINITION", + "SCHEMA", + "SCALAR", + "OBJECT", + "FIELD_DEFINITION", + "ARGUMENT_DEFINITION", + "INTERFACE", + "UNION", + "ENUM", + "ENUM_VALUE", + "INPUT_OBJECT", + "INPUT_FIELD_DEFINITION", + ], + ) } diff --git a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap index 234a90d89645..a206d536132a 100644 --- a/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap +++ b/crates/biome_graphql_parser/tests/graphql_test_suite/err/definitions/directive_definition.graphql.snap @@ -319,7 +319,7 @@ GraphqlRoot { ``` directive_definition.graphql:3:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found 'directive'. + × Expected a valid directive location 1 │ directive @example on | 2 │ @@ -328,14 +328,27 @@ directive_definition.graphql:3:1 parse ━━━━━━━━━━━━━ 4 │ 5 │ directive example on | ARGUMENT_DEFINITION - i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. - - 1 │ directive @example on | - 2 │ - > 3 │ directive @ on | ARGUMENT_DEFINITION - │ ^^^^^^^^^ - 4 │ - 5 │ directive example on | ARGUMENT_DEFINITION + i Must be one of: + + - QUERY + - MUTATION + - SUBSCRIPTION + - FIELD + - FRAGMENT_DEFINITION + - FRAGMENT_SPREAD + - INLINE_FRAGMENT + - VARIABLE_DEFINITION + - SCHEMA + - SCALAR + - OBJECT + - FIELD_DEFINITION + - ARGUMENT_DEFINITION + - INTERFACE + - UNION + - ENUM + - ENUM_VALUE + - INPUT_OBJECT + - INPUT_FIELD_DEFINITION directive_definition.graphql:3:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -396,7 +409,7 @@ directive_definition.graphql:6:19 parse ━━━━━━━━━━━━━ directive_definition.graphql:13:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found 'directive'. + × Expected a valid directive location 11 │ | 12 │ @@ -405,14 +418,27 @@ directive_definition.graphql:13:1 parse ━━━━━━━━━━━━━ 14 │ 15 │ directve @example on - i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. - - 11 │ | - 12 │ - > 13 │ directive @delegateField(: !) repeatable on OBJECT | INTERFACE - │ ^^^^^^^^^ - 14 │ - 15 │ directve @example on + i Must be one of: + + - QUERY + - MUTATION + - SUBSCRIPTION + - FIELD + - FRAGMENT_DEFINITION + - FRAGMENT_SPREAD + - INLINE_FRAGMENT + - VARIABLE_DEFINITION + - SCHEMA + - SCALAR + - OBJECT + - FIELD_DEFINITION + - ARGUMENT_DEFINITION + - INTERFACE + - UNION + - ENUM + - ENUM_VALUE + - INPUT_OBJECT + - INPUT_FIELD_DEFINITION directive_definition.graphql:13:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -469,8 +495,7 @@ directive_definition.graphql:15:1 parse ━━━━━━━━━━━━━ directive_definition.graphql:19:5 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION but instead found '123 - | name'. + × Expected a valid directive location 17 │ directive @example on 18 │ | # @@ -480,14 +505,26 @@ directive_definition.graphql:19:5 parse ━━━━━━━━━━━━━ │ ^^^^^^ 21 │ - i Expected a QUERY, a MUTATION, a SUBSCRIPTION, a FIELD, a FRAGMENT_DEFINITION, a FRAGMENT_SPREAD, a INLINE_FRAGMENT, a VARIABLE_DEFINITION, a SCHEMA, a SCALAR, a OBJECT, a FIELD_DEFINITION, a ARGUMENT_DEFINITION, a INTERFACE, a UNION, a ENUM, a ENUM_VALUE, a INPUT_OBJECT, or a INPUT_FIELD_DEFINITION here. - - 17 │ directive @example on - 18 │ | # - > 19 │ | 123 - │ ^^^ - > 20 │ | name - │ ^^^^^^ - 21 │ + i Must be one of: + + - QUERY + - MUTATION + - SUBSCRIPTION + - FIELD + - FRAGMENT_DEFINITION + - FRAGMENT_SPREAD + - INLINE_FRAGMENT + - VARIABLE_DEFINITION + - SCHEMA + - SCALAR + - OBJECT + - FIELD_DEFINITION + - ARGUMENT_DEFINITION + - INTERFACE + - UNION + - ENUM + - ENUM_VALUE + - INPUT_OBJECT + - INPUT_FIELD_DEFINITION ```