@@ -158,11 +158,25 @@ describe('Parser', () => {
158
158
# This comment has a \u0A0A multi-byte character.
159
159
{ field(arg: "Has a \u0A0A multi-byte character.") }
160
160
` ) ;
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 ,
165
163
) ;
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.' ) ;
166
180
} ) ;
167
181
168
182
it ( 'parses kitchen sink' , ( ) => {
@@ -254,6 +268,7 @@ describe('Parser', () => {
254
268
{
255
269
kind : Kind . OPERATION_DEFINITION ,
256
270
loc : { start : 0 , end : 40 } ,
271
+ description : undefined ,
257
272
operation : 'query' ,
258
273
name : undefined ,
259
274
variableDefinitions : [ ] ,
@@ -330,6 +345,7 @@ describe('Parser', () => {
330
345
331
346
it ( 'creates ast from nameless query without variables' , ( ) => {
332
347
const result = parse ( dedent `
348
+ "Query description"
333
349
query {
334
350
node {
335
351
id
@@ -339,41 +355,47 @@ describe('Parser', () => {
339
355
340
356
expectJSON ( result ) . toDeepEqual ( {
341
357
kind : Kind . DOCUMENT ,
342
- loc : { start : 0 , end : 29 } ,
358
+ loc : { start : 0 , end : 49 } ,
343
359
definitions : [
344
360
{
345
361
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
+ } ,
347
369
operation : 'query' ,
348
370
name : undefined ,
349
371
variableDefinitions : [ ] ,
350
372
directives : [ ] ,
351
373
selectionSet : {
352
374
kind : Kind . SELECTION_SET ,
353
- loc : { start : 6 , end : 29 } ,
375
+ loc : { start : 26 , end : 49 } ,
354
376
selections : [
355
377
{
356
378
kind : Kind . FIELD ,
357
- loc : { start : 10 , end : 27 } ,
379
+ loc : { start : 30 , end : 47 } ,
358
380
alias : undefined ,
359
381
name : {
360
382
kind : Kind . NAME ,
361
- loc : { start : 10 , end : 14 } ,
383
+ loc : { start : 30 , end : 34 } ,
362
384
value : 'node' ,
363
385
} ,
364
386
arguments : [ ] ,
365
387
directives : [ ] ,
366
388
selectionSet : {
367
389
kind : Kind . SELECTION_SET ,
368
- loc : { start : 15 , end : 27 } ,
390
+ loc : { start : 35 , end : 47 } ,
369
391
selections : [
370
392
{
371
393
kind : Kind . FIELD ,
372
- loc : { start : 21 , end : 23 } ,
394
+ loc : { start : 41 , end : 43 } ,
373
395
alias : undefined ,
374
396
name : {
375
397
kind : Kind . NAME ,
376
- loc : { start : 21 , end : 23 } ,
398
+ loc : { start : 41 , end : 43 } ,
377
399
value : 'id' ,
378
400
} ,
379
401
arguments : [ ] ,
@@ -652,4 +674,93 @@ describe('Parser', () => {
652
674
} ) ;
653
675
} ) ;
654
676
} ) ;
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
+ } ) ;
655
766
} ) ;
0 commit comments