@@ -158,11 +158,25 @@ describe('Parser', () => {
158158 # This comment has a \u0A0A multi-byte character.
159159 { field(arg: "Has a \u0A0A multi-byte character.") }
160160 ` ) ;
161-
162- expect ( ast ) . to . have . nested . property (
163- 'definitions[0].selectionSet.selections[0].arguments[0].value.value' ,
164- 'Has a \u0A0A multi-byte character.' ,
161+ const opDef = ast . definitions . find (
162+ ( d ) => d . kind === Kind . OPERATION_DEFINITION ,
165163 ) ;
164+ if ( ! opDef || opDef . kind !== Kind . OPERATION_DEFINITION ) {
165+ throw new Error ( 'No operation definition found' ) ;
166+ }
167+ const fieldSel = opDef . selectionSet . selections [ 0 ] ;
168+ if ( fieldSel . kind !== Kind . FIELD ) {
169+ throw new Error ( 'Expected a field selection' ) ;
170+ }
171+ const args = fieldSel . arguments ;
172+ if ( ! args || args . length === 0 ) {
173+ throw new Error ( 'No arguments found' ) ;
174+ }
175+ const argValueNode = args [ 0 ] . value ;
176+ if ( argValueNode . kind !== Kind . STRING ) {
177+ throw new Error ( 'Expected a string value' ) ;
178+ }
179+ expect ( argValueNode . value ) . to . equal ( 'Has a \u0A0A multi-byte character.' ) ;
166180 } ) ;
167181
168182 it ( 'parses kitchen sink' , ( ) => {
@@ -254,6 +268,7 @@ describe('Parser', () => {
254268 {
255269 kind : Kind . OPERATION_DEFINITION ,
256270 loc : { start : 0 , end : 40 } ,
271+ description : undefined ,
257272 operation : 'query' ,
258273 name : undefined ,
259274 variableDefinitions : [ ] ,
@@ -330,6 +345,7 @@ describe('Parser', () => {
330345
331346 it ( 'creates ast from nameless query without variables' , ( ) => {
332347 const result = parse ( dedent `
348+ "Query description"
333349 query {
334350 node {
335351 id
@@ -339,41 +355,47 @@ describe('Parser', () => {
339355
340356 expectJSON ( result ) . toDeepEqual ( {
341357 kind : Kind . DOCUMENT ,
342- loc : { start : 0 , end : 29 } ,
358+ loc : { start : 0 , end : 49 } ,
343359 definitions : [
344360 {
345361 kind : Kind . OPERATION_DEFINITION ,
346- loc : { start : 0 , end : 29 } ,
362+ loc : { start : 0 , end : 49 } ,
363+ description : {
364+ kind : Kind . STRING ,
365+ loc : { start : 0 , end : 19 } ,
366+ block : false ,
367+ value : 'Query description' ,
368+ } ,
347369 operation : 'query' ,
348370 name : undefined ,
349371 variableDefinitions : [ ] ,
350372 directives : [ ] ,
351373 selectionSet : {
352374 kind : Kind . SELECTION_SET ,
353- loc : { start : 6 , end : 29 } ,
375+ loc : { start : 26 , end : 49 } ,
354376 selections : [
355377 {
356378 kind : Kind . FIELD ,
357- loc : { start : 10 , end : 27 } ,
379+ loc : { start : 30 , end : 47 } ,
358380 alias : undefined ,
359381 name : {
360382 kind : Kind . NAME ,
361- loc : { start : 10 , end : 14 } ,
383+ loc : { start : 30 , end : 34 } ,
362384 value : 'node' ,
363385 } ,
364386 arguments : [ ] ,
365387 directives : [ ] ,
366388 selectionSet : {
367389 kind : Kind . SELECTION_SET ,
368- loc : { start : 15 , end : 27 } ,
390+ loc : { start : 35 , end : 47 } ,
369391 selections : [
370392 {
371393 kind : Kind . FIELD ,
372- loc : { start : 21 , end : 23 } ,
394+ loc : { start : 41 , end : 43 } ,
373395 alias : undefined ,
374396 name : {
375397 kind : Kind . NAME ,
376- loc : { start : 21 , end : 23 } ,
398+ loc : { start : 41 , end : 43 } ,
377399 value : 'id' ,
378400 } ,
379401 arguments : [ ] ,
@@ -652,4 +674,93 @@ describe('Parser', () => {
652674 } ) ;
653675 } ) ;
654676 } ) ;
677+
678+ describe ( 'operation and variable definition descriptions' , ( ) => {
679+ it ( 'parses operation with description and variable descriptions' , ( ) => {
680+ const result = parse ( dedent `
681+ "Operation description"
682+ query myQuery(
683+ "Variable a description"
684+ $a: Int,
685+ """Variable b\nmultiline description"""
686+ $b: String
687+ ) {
688+ field(a: $a, b: $b)
689+ }
690+ ` ) ;
691+ // Find the operation definition
692+ const opDef = result . definitions . find (
693+ ( d ) => d . kind === Kind . OPERATION_DEFINITION ,
694+ ) ;
695+ if ( ! opDef || opDef . kind !== Kind . OPERATION_DEFINITION ) {
696+ throw new Error ( 'No operation definition found' ) ;
697+ }
698+ expect ( opDef . description ?. value ) . to . equal ( 'Operation description' ) ;
699+ expect ( opDef . name ?. value ) . to . equal ( 'myQuery' ) ;
700+ expect ( opDef . variableDefinitions ?. [ 0 ] . description ?. value ) . to . equal (
701+ 'Variable a description' ,
702+ ) ;
703+ expect ( opDef . variableDefinitions ?. [ 0 ] . description ?. block ) . to . equal ( false ) ;
704+ expect ( opDef . variableDefinitions ?. [ 1 ] . description ?. value ) . to . equal (
705+ 'Variable b\nmultiline description' ,
706+ ) ;
707+ expect ( opDef . variableDefinitions ?. [ 1 ] . description ?. block ) . to . equal ( true ) ;
708+ expect ( opDef . variableDefinitions ?. [ 0 ] . variable . name . value ) . to . equal ( 'a' ) ;
709+ expect ( opDef . variableDefinitions ?. [ 1 ] . variable . name . value ) . to . equal ( 'b' ) ;
710+ // Check type names safely
711+ const typeA = opDef . variableDefinitions ?. [ 0 ] . type ;
712+ if ( typeA && typeA . kind === Kind . NAMED_TYPE ) {
713+ expect ( typeA . name . value ) . to . equal ( 'Int' ) ;
714+ }
715+ const typeB = opDef . variableDefinitions ?. [ 1 ] . type ;
716+ if ( typeB && typeB . kind === Kind . NAMED_TYPE ) {
717+ expect ( typeB . name . value ) . to . equal ( 'String' ) ;
718+ }
719+ } ) ;
720+
721+ it ( 'parses variable definition with description, default value, and directives' , ( ) => {
722+ const result = parse ( dedent `
723+ query (
724+ "desc"
725+ $foo: Int = 42 @dir
726+ ) {
727+ field(foo: $foo)
728+ }
729+ ` ) ;
730+ const opDef = result . definitions . find (
731+ ( d ) => d . kind === Kind . OPERATION_DEFINITION ,
732+ ) ;
733+ if ( ! opDef || opDef . kind !== Kind . OPERATION_DEFINITION ) {
734+ throw new Error ( 'No operation definition found' ) ;
735+ }
736+ const varDef = opDef . variableDefinitions ?. [ 0 ] ;
737+ expect ( varDef ?. description ?. value ) . to . equal ( 'desc' ) ;
738+ expect ( varDef ?. variable . name . value ) . to . equal ( 'foo' ) ;
739+ if ( varDef ?. type . kind === Kind . NAMED_TYPE ) {
740+ expect ( varDef . type . name . value ) . to . equal ( 'Int' ) ;
741+ }
742+ if ( varDef ?. defaultValue && 'value' in varDef . defaultValue ) {
743+ expect ( varDef . defaultValue . value ) . to . equal ( '42' ) ;
744+ }
745+ expect ( varDef ?. directives ?. [ 0 ] . name . value ) . to . equal ( 'dir' ) ;
746+ } ) ;
747+
748+ it ( 'parses fragment with variable description (legacy)' , ( ) => {
749+ const result = parse ( 'fragment Foo("desc" $foo: Int) on Bar { baz }' , {
750+ allowLegacyFragmentVariables : true ,
751+ } ) ;
752+ const fragDef = result . definitions . find (
753+ ( d ) => d . kind === Kind . FRAGMENT_DEFINITION ,
754+ ) ;
755+ if ( ! fragDef || fragDef . kind !== Kind . FRAGMENT_DEFINITION ) {
756+ throw new Error ( 'No fragment definition found' ) ;
757+ }
758+ const varDef = fragDef . variableDefinitions ?. [ 0 ] ;
759+ expect ( varDef ?. description ?. value ) . to . equal ( 'desc' ) ;
760+ expect ( varDef ?. variable . name . value ) . to . equal ( 'foo' ) ;
761+ if ( varDef ?. type . kind === Kind . NAMED_TYPE ) {
762+ expect ( varDef . type . name . value ) . to . equal ( 'Int' ) ;
763+ }
764+ } ) ;
765+ } ) ;
655766} ) ;
0 commit comments