1+ use crate :: parser:: grammar:: description;
12use crate :: parser:: grammar:: directive;
23use crate :: parser:: grammar:: name;
34use crate :: parser:: grammar:: selection;
@@ -8,13 +9,43 @@ use crate::SyntaxKind;
89use crate :: TokenKind ;
910use crate :: T ;
1011
11- /// See: https://spec.graphql.org/October2021/#OperationDefinition
12+ /// See: https://spec.graphql.org/September2025/#sec-Language.Operations
1213///
1314/// *OperationDefinition*:
14- /// OperationType Name? VariableDefinitions? Directives? SelectionSet
15+ /// Description? OperationType Name? VariableDefinitions? Directives? SelectionSet
1516/// SelectionSet
1617pub ( crate ) fn operation_definition ( p : & mut Parser ) {
1718 match p. peek ( ) {
19+ Some ( TokenKind :: StringValue ) => {
20+ // Description found - must be full operation definition, not shorthand
21+ let _g = p. start_node ( SyntaxKind :: OPERATION_DEFINITION ) ;
22+
23+ description:: description ( p) ;
24+
25+ // After description, we must have an operation type
26+ if let Some ( TokenKind :: Name ) = p. peek ( ) {
27+ operation_type ( p) ;
28+ } else {
29+ return p. err_and_pop ( "expected an Operation Type after description" ) ;
30+ }
31+
32+ if let Some ( TokenKind :: Name ) = p. peek ( ) {
33+ name:: name ( p) ;
34+ }
35+
36+ if let Some ( T ! [ '(' ] ) = p. peek ( ) {
37+ variable:: variable_definitions ( p)
38+ }
39+
40+ if let Some ( T ! [ @] ) = p. peek ( ) {
41+ directive:: directives ( p, Constness :: NotConst ) ;
42+ }
43+
44+ match p. peek ( ) {
45+ Some ( T ! [ '{' ] ) => selection:: selection_set ( p) ,
46+ _ => p. err_and_pop ( "expected a Selection Set" ) ,
47+ }
48+ }
1849 Some ( TokenKind :: Name ) => {
1950 let _g = p. start_node ( SyntaxKind :: OPERATION_DEFINITION ) ;
2051
@@ -46,7 +77,7 @@ pub(crate) fn operation_definition(p: &mut Parser) {
4677 }
4778}
4879
49- /// See: https://spec.graphql.org/October2021/#OperationType
80+ /// See: https://spec.graphql.org/September2025/#sec-Language.Operations
5081///
5182/// *OperationType*: one of
5283/// **query** **mutation** **subscription**
@@ -66,15 +97,25 @@ pub(crate) fn operation_type(p: &mut Parser) {
6697mod test {
6798 use crate :: Parser ;
6899
69- // NOTE @lrlna: related PR to the spec to avoid this issue:
70- // https://github.com/graphql/graphql-spec/pull/892
100+ // NOTE @lrlna: Descriptions on operations are now supported in September 2025 spec
101+ // https://github.com/graphql/graphql-spec/pull/1170
71102 #[ test]
72- fn it_continues_parsing_when_operation_definition_starts_with_description ( ) {
73- let input = "\" description \" { }" ;
103+ fn it_parses_operation_definition_with_description ( ) {
104+ let input = "\" A test query \" query Test { field }" ;
74105 let parser = Parser :: new ( input) ;
75106 let cst = parser. parse ( ) ;
76107
77- assert_eq ! ( cst. errors( ) . len( ) , 2 ) ;
108+ assert_eq ! ( cst. errors( ) . len( ) , 0 ) ;
78109 assert_eq ! ( cst. document( ) . definitions( ) . count( ) , 1 ) ;
79110 }
111+
112+ #[ test]
113+ fn it_errors_on_shorthand_query_with_description ( ) {
114+ let input = "\" description\" {}" ;
115+ let parser = Parser :: new ( input) ;
116+ let cst = parser. parse ( ) ;
117+
118+ // Should error because descriptions are not allowed on shorthand queries
119+ assert ! ( cst. errors( ) . len( ) > 0 ) ;
120+ }
80121}
0 commit comments