···
1
+
// See: https://github.com/graphql/graphql-js/blob/976d64b/src/language/__tests__/visitor-test.ts
3
+
import { Kind, parse } from 'graphql';
4
+
import { visit, visitInParallel, BREAK } from '../visitor';
6
+
const kitchenSinkQuery: string = String.raw`
7
+
query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery {
8
+
whoever123is: node(id: [123, 456]) {
10
+
... on User @onInlineFragment {
13
+
alias: field1(first: 10, after: $foo) @include(if: $foo) {
15
+
...frag @onFragmentSpread
19
+
... @skip(unless: $foo) {
27
+
mutation likeStory @onMutation {
28
+
like(story: 123) @onField {
34
+
subscription StoryLikeSubscription(
35
+
$input: StoryLikeSubscribeInput @onVariableDefinition
38
+
storyLikeSubscribe(input: $input) {
49
+
fragment frag on Friend @onFragmentDefinition {
56
+
block string uses \"""
62
+
unnamed(truthy: true, falsy: false, nullish: null)
70
+
function checkVisitorFnArgs(ast, args, isEdited = false) {
71
+
const [node, key, parent, path, ancestors] = args;
73
+
expect(node).toBeInstanceOf(Object);
74
+
expect(Object.values(Kind)).toContain(node.kind);
76
+
const isRoot = key === undefined;
79
+
expect(node).toEqual(ast);
81
+
expect(parent).toEqual(undefined);
82
+
expect(path).toEqual([]);
83
+
expect(ancestors).toEqual([]);
87
+
expect(typeof key).toMatch(/number|string/);
89
+
expect(parent).toHaveProperty([key]);
91
+
expect(path).toBeInstanceOf(Array);
92
+
expect(path[path.length - 1]).toEqual(key);
94
+
expect(ancestors).toBeInstanceOf(Array);
95
+
expect(ancestors.length).toEqual(path.length - 1);
98
+
let currentNode = ast;
99
+
for (let i = 0; i < ancestors.length; ++i) {
100
+
expect(ancestors[i]).toEqual(currentNode);
102
+
currentNode = currentNode[path[i]];
103
+
expect(currentNode).not.toEqual(undefined);
106
+
// expect(parent).toEqual(currentNode);
107
+
// expect(parent[key]).toEqual(node);
111
+
function isNode(node) {
112
+
return node != null && typeof node.kind === 'string';
115
+
function getValue(node) {
116
+
return 'value' in node ? node.value : undefined;
119
+
describe('Visitor', () => {
120
+
it('handles empty visitor', () => {
121
+
const ast = parse('{ a }', { noLocation: true });
122
+
expect(() => visit(ast, {})).not.toThrow();
125
+
it('validates path argument', () => {
126
+
const visited: Array<any> = [];
128
+
const ast = parse('{ a }', { noLocation: true });
131
+
enter(_node, _key, _parent, path) {
132
+
checkVisitorFnArgs(ast, arguments);
133
+
visited.push(['enter', path.slice()]);
135
+
leave(_node, _key, _parent, path) {
136
+
checkVisitorFnArgs(ast, arguments);
137
+
visited.push(['leave', path.slice()]);
141
+
expect(visited).toEqual([
143
+
['enter', ['definitions', 0]],
144
+
['enter', ['definitions', 0, 'selectionSet']],
145
+
['enter', ['definitions', 0, 'selectionSet', 'selections', 0]],
146
+
['enter', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
147
+
['leave', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],
148
+
['leave', ['definitions', 0, 'selectionSet', 'selections', 0]],
149
+
['leave', ['definitions', 0, 'selectionSet']],
150
+
['leave', ['definitions', 0]],
155
+
it('validates ancestors argument', () => {
156
+
const ast = parse('{ a }', { noLocation: true });
157
+
const visitedNodes: Array<any> = [];
160
+
enter(node, key, parent, _path, ancestors) {
161
+
const inArray = typeof key === 'number';
163
+
visitedNodes.push(parent);
165
+
visitedNodes.push(node);
167
+
const expectedAncestors = visitedNodes.slice(0, -2);
168
+
expect(ancestors).toEqual(expectedAncestors);
170
+
leave(_node, key, _parent, _path, ancestors) {
171
+
const expectedAncestors = visitedNodes.slice(0, -2);
172
+
expect(ancestors).toEqual(expectedAncestors);
174
+
const inArray = typeof key === 'number';
176
+
visitedNodes.pop();
178
+
visitedNodes.pop();
183
+
it('allows editing a node both on enter and on leave', () => {
184
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
186
+
let selectionSet: SelectionSetNode;
188
+
const editedAST = visit(ast, {
189
+
OperationDefinition: {
191
+
checkVisitorFnArgs(ast, arguments);
192
+
selectionSet = node.selectionSet;
196
+
kind: 'SelectionSet',
203
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
213
+
expect(editedAST).toEqual({
217
+
...ast.definitions[0],
225
+
it('allows editing the root node on enter and on leave', () => {
226
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
228
+
const { definitions } = ast;
230
+
const editedAST = visit(ast, {
233
+
checkVisitorFnArgs(ast, arguments);
241
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
251
+
expect(editedAST).toEqual({
258
+
it('allows for editing on enter', () => {
259
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
260
+
const editedAST = visit(ast, {
262
+
checkVisitorFnArgs(ast, arguments);
263
+
if (node.kind === 'Field' && node.name.value === 'b') {
269
+
expect(ast).toEqual(parse('{ a, b, c { a, b, c } }', { noLocation: true }));
271
+
expect(editedAST).toEqual(
272
+
parse('{ a, c { a, c } }', { noLocation: true })
276
+
it('allows for editing on leave', () => {
277
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
278
+
const editedAST = visit(ast, {
280
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
281
+
if (node.kind === 'Field' && node.name.value === 'b') {
287
+
expect(ast).toEqual(parse('{ a, b, c { a, b, c } }', { noLocation: true }));
289
+
expect(editedAST).toEqual(
290
+
parse('{ a, c { a, c } }', { noLocation: true })
294
+
it('ignores false returned on leave', () => {
295
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
296
+
const returnedAST = visit(ast, {
302
+
expect(returnedAST).toEqual(
303
+
parse('{ a, b, c { a, b, c } }', { noLocation: true })
307
+
it('visits edited node', () => {
308
+
const addedField = {
312
+
value: '__typename',
316
+
let didVisitAddedField;
318
+
const ast = parse('{ a { x } }', { noLocation: true });
321
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
322
+
if (node.kind === 'Field' && node.name.value === 'a') {
325
+
selectionSet: [addedField, node.selectionSet],
328
+
if (node === addedField) {
329
+
didVisitAddedField = true;
334
+
expect(didVisitAddedField).toEqual(true);
337
+
it('allows skipping a sub-tree', () => {
338
+
const visited: Array<any> = [];
340
+
const ast = parse('{ a, b { x }, c }', { noLocation: true });
343
+
checkVisitorFnArgs(ast, arguments);
344
+
visited.push(['enter', node.kind, getValue(node)]);
345
+
if (node.kind === 'Field' && node.name.value === 'b') {
351
+
checkVisitorFnArgs(ast, arguments);
352
+
visited.push(['leave', node.kind, getValue(node)]);
356
+
expect(visited).toEqual([
357
+
['enter', 'Document', undefined],
358
+
['enter', 'OperationDefinition', undefined],
359
+
['enter', 'SelectionSet', undefined],
360
+
['enter', 'Field', undefined],
361
+
['enter', 'Name', 'a'],
362
+
['leave', 'Name', 'a'],
363
+
['leave', 'Field', undefined],
364
+
['enter', 'Field', undefined],
365
+
['enter', 'Field', undefined],
366
+
['enter', 'Name', 'c'],
367
+
['leave', 'Name', 'c'],
368
+
['leave', 'Field', undefined],
369
+
['leave', 'SelectionSet', undefined],
370
+
['leave', 'OperationDefinition', undefined],
371
+
['leave', 'Document', undefined],
375
+
it('allows early exit while visiting', () => {
376
+
const visited: Array<any> = [];
378
+
const ast = parse('{ a, b { x }, c }', { noLocation: true });
381
+
checkVisitorFnArgs(ast, arguments);
382
+
visited.push(['enter', node.kind, getValue(node)]);
383
+
if (node.kind === 'Name' && node.value === 'x') {
388
+
checkVisitorFnArgs(ast, arguments);
389
+
visited.push(['leave', node.kind, getValue(node)]);
393
+
expect(visited).toEqual([
394
+
['enter', 'Document', undefined],
395
+
['enter', 'OperationDefinition', undefined],
396
+
['enter', 'SelectionSet', undefined],
397
+
['enter', 'Field', undefined],
398
+
['enter', 'Name', 'a'],
399
+
['leave', 'Name', 'a'],
400
+
['leave', 'Field', undefined],
401
+
['enter', 'Field', undefined],
402
+
['enter', 'Name', 'b'],
403
+
['leave', 'Name', 'b'],
404
+
['enter', 'SelectionSet', undefined],
405
+
['enter', 'Field', undefined],
406
+
['enter', 'Name', 'x'],
410
+
it('allows early exit while leaving', () => {
411
+
const visited: Array<any> = [];
413
+
const ast = parse('{ a, b { x }, c }', { noLocation: true });
416
+
checkVisitorFnArgs(ast, arguments);
417
+
visited.push(['enter', node.kind, getValue(node)]);
421
+
checkVisitorFnArgs(ast, arguments);
422
+
visited.push(['leave', node.kind, getValue(node)]);
423
+
if (node.kind === 'Name' && node.value === 'x') {
429
+
expect(visited).toEqual([
430
+
['enter', 'Document', undefined],
431
+
['enter', 'OperationDefinition', undefined],
432
+
['enter', 'SelectionSet', undefined],
433
+
['enter', 'Field', undefined],
434
+
['enter', 'Name', 'a'],
435
+
['leave', 'Name', 'a'],
436
+
['leave', 'Field', undefined],
437
+
['enter', 'Field', undefined],
438
+
['enter', 'Name', 'b'],
439
+
['leave', 'Name', 'b'],
440
+
['enter', 'SelectionSet', undefined],
441
+
['enter', 'Field', undefined],
442
+
['enter', 'Name', 'x'],
443
+
['leave', 'Name', 'x'],
447
+
it('allows a named functions visitor API', () => {
448
+
const visited: Array<any> = [];
450
+
const ast = parse('{ a, b { x }, c }', { noLocation: true });
453
+
checkVisitorFnArgs(ast, arguments);
454
+
visited.push(['enter', node.kind, getValue(node)]);
458
+
checkVisitorFnArgs(ast, arguments);
459
+
visited.push(['enter', node.kind, getValue(node)]);
462
+
checkVisitorFnArgs(ast, arguments);
463
+
visited.push(['leave', node.kind, getValue(node)]);
468
+
expect(visited).toEqual([
469
+
['enter', 'SelectionSet', undefined],
470
+
['enter', 'Name', 'a'],
471
+
['enter', 'Name', 'b'],
472
+
['enter', 'SelectionSet', undefined],
473
+
['enter', 'Name', 'x'],
474
+
['leave', 'SelectionSet', undefined],
475
+
['enter', 'Name', 'c'],
476
+
['leave', 'SelectionSet', undefined],
480
+
it('visits kitchen sink', () => {
481
+
const ast = parse(kitchenSinkQuery);
482
+
const visited: Array<any> = [];
483
+
const argsStack: Array<any> = [];
486
+
enter(node, key, parent) {
491
+
isNode(parent) ? parent.kind : undefined,
494
+
checkVisitorFnArgs(ast, arguments);
495
+
argsStack.push([...arguments]);
498
+
leave(node, key, parent) {
503
+
isNode(parent) ? parent.kind : undefined,
506
+
expect(argsStack.pop()).toEqual([...arguments]);
510
+
expect(argsStack).toEqual([]);
511
+
expect(visited).toEqual([
512
+
['enter', 'Document', undefined, undefined],
513
+
['enter', 'OperationDefinition', 0, undefined],
514
+
['enter', 'Name', 'name', 'OperationDefinition'],
515
+
['leave', 'Name', 'name', 'OperationDefinition'],
516
+
['enter', 'VariableDefinition', 0, undefined],
517
+
['enter', 'Variable', 'variable', 'VariableDefinition'],
518
+
['enter', 'Name', 'name', 'Variable'],
519
+
['leave', 'Name', 'name', 'Variable'],
520
+
['leave', 'Variable', 'variable', 'VariableDefinition'],
521
+
['enter', 'NamedType', 'type', 'VariableDefinition'],
522
+
['enter', 'Name', 'name', 'NamedType'],
523
+
['leave', 'Name', 'name', 'NamedType'],
524
+
['leave', 'NamedType', 'type', 'VariableDefinition'],
525
+
['leave', 'VariableDefinition', 0, undefined],
526
+
['enter', 'VariableDefinition', 1, undefined],
527
+
['enter', 'Variable', 'variable', 'VariableDefinition'],
528
+
['enter', 'Name', 'name', 'Variable'],
529
+
['leave', 'Name', 'name', 'Variable'],
530
+
['leave', 'Variable', 'variable', 'VariableDefinition'],
531
+
['enter', 'NamedType', 'type', 'VariableDefinition'],
532
+
['enter', 'Name', 'name', 'NamedType'],
533
+
['leave', 'Name', 'name', 'NamedType'],
534
+
['leave', 'NamedType', 'type', 'VariableDefinition'],
535
+
['enter', 'EnumValue', 'defaultValue', 'VariableDefinition'],
536
+
['leave', 'EnumValue', 'defaultValue', 'VariableDefinition'],
537
+
['leave', 'VariableDefinition', 1, undefined],
538
+
['enter', 'Directive', 0, undefined],
539
+
['enter', 'Name', 'name', 'Directive'],
540
+
['leave', 'Name', 'name', 'Directive'],
541
+
['leave', 'Directive', 0, undefined],
542
+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
543
+
['enter', 'Field', 0, undefined],
544
+
['enter', 'Name', 'alias', 'Field'],
545
+
['leave', 'Name', 'alias', 'Field'],
546
+
['enter', 'Name', 'name', 'Field'],
547
+
['leave', 'Name', 'name', 'Field'],
548
+
['enter', 'Argument', 0, undefined],
549
+
['enter', 'Name', 'name', 'Argument'],
550
+
['leave', 'Name', 'name', 'Argument'],
551
+
['enter', 'ListValue', 'value', 'Argument'],
552
+
['enter', 'IntValue', 0, undefined],
553
+
['leave', 'IntValue', 0, undefined],
554
+
['enter', 'IntValue', 1, undefined],
555
+
['leave', 'IntValue', 1, undefined],
556
+
['leave', 'ListValue', 'value', 'Argument'],
557
+
['leave', 'Argument', 0, undefined],
558
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
559
+
['enter', 'Field', 0, undefined],
560
+
['enter', 'Name', 'name', 'Field'],
561
+
['leave', 'Name', 'name', 'Field'],
562
+
['leave', 'Field', 0, undefined],
563
+
['enter', 'InlineFragment', 1, undefined],
564
+
['enter', 'NamedType', 'typeCondition', 'InlineFragment'],
565
+
['enter', 'Name', 'name', 'NamedType'],
566
+
['leave', 'Name', 'name', 'NamedType'],
567
+
['leave', 'NamedType', 'typeCondition', 'InlineFragment'],
568
+
['enter', 'Directive', 0, undefined],
569
+
['enter', 'Name', 'name', 'Directive'],
570
+
['leave', 'Name', 'name', 'Directive'],
571
+
['leave', 'Directive', 0, undefined],
572
+
['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],
573
+
['enter', 'Field', 0, undefined],
574
+
['enter', 'Name', 'name', 'Field'],
575
+
['leave', 'Name', 'name', 'Field'],
576
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
577
+
['enter', 'Field', 0, undefined],
578
+
['enter', 'Name', 'name', 'Field'],
579
+
['leave', 'Name', 'name', 'Field'],
580
+
['leave', 'Field', 0, undefined],
581
+
['enter', 'Field', 1, undefined],
582
+
['enter', 'Name', 'alias', 'Field'],
583
+
['leave', 'Name', 'alias', 'Field'],
584
+
['enter', 'Name', 'name', 'Field'],
585
+
['leave', 'Name', 'name', 'Field'],
586
+
['enter', 'Argument', 0, undefined],
587
+
['enter', 'Name', 'name', 'Argument'],
588
+
['leave', 'Name', 'name', 'Argument'],
589
+
['enter', 'IntValue', 'value', 'Argument'],
590
+
['leave', 'IntValue', 'value', 'Argument'],
591
+
['leave', 'Argument', 0, undefined],
592
+
['enter', 'Argument', 1, undefined],
593
+
['enter', 'Name', 'name', 'Argument'],
594
+
['leave', 'Name', 'name', 'Argument'],
595
+
['enter', 'Variable', 'value', 'Argument'],
596
+
['enter', 'Name', 'name', 'Variable'],
597
+
['leave', 'Name', 'name', 'Variable'],
598
+
['leave', 'Variable', 'value', 'Argument'],
599
+
['leave', 'Argument', 1, undefined],
600
+
['enter', 'Directive', 0, undefined],
601
+
['enter', 'Name', 'name', 'Directive'],
602
+
['leave', 'Name', 'name', 'Directive'],
603
+
['enter', 'Argument', 0, undefined],
604
+
['enter', 'Name', 'name', 'Argument'],
605
+
['leave', 'Name', 'name', 'Argument'],
606
+
['enter', 'Variable', 'value', 'Argument'],
607
+
['enter', 'Name', 'name', 'Variable'],
608
+
['leave', 'Name', 'name', 'Variable'],
609
+
['leave', 'Variable', 'value', 'Argument'],
610
+
['leave', 'Argument', 0, undefined],
611
+
['leave', 'Directive', 0, undefined],
612
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
613
+
['enter', 'Field', 0, undefined],
614
+
['enter', 'Name', 'name', 'Field'],
615
+
['leave', 'Name', 'name', 'Field'],
616
+
['leave', 'Field', 0, undefined],
617
+
['enter', 'FragmentSpread', 1, undefined],
618
+
['enter', 'Name', 'name', 'FragmentSpread'],
619
+
['leave', 'Name', 'name', 'FragmentSpread'],
620
+
['enter', 'Directive', 0, undefined],
621
+
['enter', 'Name', 'name', 'Directive'],
622
+
['leave', 'Name', 'name', 'Directive'],
623
+
['leave', 'Directive', 0, undefined],
624
+
['leave', 'FragmentSpread', 1, undefined],
625
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
626
+
['leave', 'Field', 1, undefined],
627
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
628
+
['leave', 'Field', 0, undefined],
629
+
['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],
630
+
['leave', 'InlineFragment', 1, undefined],
631
+
['enter', 'InlineFragment', 2, undefined],
632
+
['enter', 'Directive', 0, undefined],
633
+
['enter', 'Name', 'name', 'Directive'],
634
+
['leave', 'Name', 'name', 'Directive'],
635
+
['enter', 'Argument', 0, undefined],
636
+
['enter', 'Name', 'name', 'Argument'],
637
+
['leave', 'Name', 'name', 'Argument'],
638
+
['enter', 'Variable', 'value', 'Argument'],
639
+
['enter', 'Name', 'name', 'Variable'],
640
+
['leave', 'Name', 'name', 'Variable'],
641
+
['leave', 'Variable', 'value', 'Argument'],
642
+
['leave', 'Argument', 0, undefined],
643
+
['leave', 'Directive', 0, undefined],
644
+
['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],
645
+
['enter', 'Field', 0, undefined],
646
+
['enter', 'Name', 'name', 'Field'],
647
+
['leave', 'Name', 'name', 'Field'],
648
+
['leave', 'Field', 0, undefined],
649
+
['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],
650
+
['leave', 'InlineFragment', 2, undefined],
651
+
['enter', 'InlineFragment', 3, undefined],
652
+
['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],
653
+
['enter', 'Field', 0, undefined],
654
+
['enter', 'Name', 'name', 'Field'],
655
+
['leave', 'Name', 'name', 'Field'],
656
+
['leave', 'Field', 0, undefined],
657
+
['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],
658
+
['leave', 'InlineFragment', 3, undefined],
659
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
660
+
['leave', 'Field', 0, undefined],
661
+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
662
+
['leave', 'OperationDefinition', 0, undefined],
663
+
['enter', 'OperationDefinition', 1, undefined],
664
+
['enter', 'Name', 'name', 'OperationDefinition'],
665
+
['leave', 'Name', 'name', 'OperationDefinition'],
666
+
['enter', 'Directive', 0, undefined],
667
+
['enter', 'Name', 'name', 'Directive'],
668
+
['leave', 'Name', 'name', 'Directive'],
669
+
['leave', 'Directive', 0, undefined],
670
+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
671
+
['enter', 'Field', 0, undefined],
672
+
['enter', 'Name', 'name', 'Field'],
673
+
['leave', 'Name', 'name', 'Field'],
674
+
['enter', 'Argument', 0, undefined],
675
+
['enter', 'Name', 'name', 'Argument'],
676
+
['leave', 'Name', 'name', 'Argument'],
677
+
['enter', 'IntValue', 'value', 'Argument'],
678
+
['leave', 'IntValue', 'value', 'Argument'],
679
+
['leave', 'Argument', 0, undefined],
680
+
['enter', 'Directive', 0, undefined],
681
+
['enter', 'Name', 'name', 'Directive'],
682
+
['leave', 'Name', 'name', 'Directive'],
683
+
['leave', 'Directive', 0, undefined],
684
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
685
+
['enter', 'Field', 0, undefined],
686
+
['enter', 'Name', 'name', 'Field'],
687
+
['leave', 'Name', 'name', 'Field'],
688
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
689
+
['enter', 'Field', 0, undefined],
690
+
['enter', 'Name', 'name', 'Field'],
691
+
['leave', 'Name', 'name', 'Field'],
692
+
['enter', 'Directive', 0, undefined],
693
+
['enter', 'Name', 'name', 'Directive'],
694
+
['leave', 'Name', 'name', 'Directive'],
695
+
['leave', 'Directive', 0, undefined],
696
+
['leave', 'Field', 0, undefined],
697
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
698
+
['leave', 'Field', 0, undefined],
699
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
700
+
['leave', 'Field', 0, undefined],
701
+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
702
+
['leave', 'OperationDefinition', 1, undefined],
703
+
['enter', 'OperationDefinition', 2, undefined],
704
+
['enter', 'Name', 'name', 'OperationDefinition'],
705
+
['leave', 'Name', 'name', 'OperationDefinition'],
706
+
['enter', 'VariableDefinition', 0, undefined],
707
+
['enter', 'Variable', 'variable', 'VariableDefinition'],
708
+
['enter', 'Name', 'name', 'Variable'],
709
+
['leave', 'Name', 'name', 'Variable'],
710
+
['leave', 'Variable', 'variable', 'VariableDefinition'],
711
+
['enter', 'NamedType', 'type', 'VariableDefinition'],
712
+
['enter', 'Name', 'name', 'NamedType'],
713
+
['leave', 'Name', 'name', 'NamedType'],
714
+
['leave', 'NamedType', 'type', 'VariableDefinition'],
715
+
['enter', 'Directive', 0, undefined],
716
+
['enter', 'Name', 'name', 'Directive'],
717
+
['leave', 'Name', 'name', 'Directive'],
718
+
['leave', 'Directive', 0, undefined],
719
+
['leave', 'VariableDefinition', 0, undefined],
720
+
['enter', 'Directive', 0, undefined],
721
+
['enter', 'Name', 'name', 'Directive'],
722
+
['leave', 'Name', 'name', 'Directive'],
723
+
['leave', 'Directive', 0, undefined],
724
+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
725
+
['enter', 'Field', 0, undefined],
726
+
['enter', 'Name', 'name', 'Field'],
727
+
['leave', 'Name', 'name', 'Field'],
728
+
['enter', 'Argument', 0, undefined],
729
+
['enter', 'Name', 'name', 'Argument'],
730
+
['leave', 'Name', 'name', 'Argument'],
731
+
['enter', 'Variable', 'value', 'Argument'],
732
+
['enter', 'Name', 'name', 'Variable'],
733
+
['leave', 'Name', 'name', 'Variable'],
734
+
['leave', 'Variable', 'value', 'Argument'],
735
+
['leave', 'Argument', 0, undefined],
736
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
737
+
['enter', 'Field', 0, undefined],
738
+
['enter', 'Name', 'name', 'Field'],
739
+
['leave', 'Name', 'name', 'Field'],
740
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
741
+
['enter', 'Field', 0, undefined],
742
+
['enter', 'Name', 'name', 'Field'],
743
+
['leave', 'Name', 'name', 'Field'],
744
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
745
+
['enter', 'Field', 0, undefined],
746
+
['enter', 'Name', 'name', 'Field'],
747
+
['leave', 'Name', 'name', 'Field'],
748
+
['leave', 'Field', 0, undefined],
749
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
750
+
['leave', 'Field', 0, undefined],
751
+
['enter', 'Field', 1, undefined],
752
+
['enter', 'Name', 'name', 'Field'],
753
+
['leave', 'Name', 'name', 'Field'],
754
+
['enter', 'SelectionSet', 'selectionSet', 'Field'],
755
+
['enter', 'Field', 0, undefined],
756
+
['enter', 'Name', 'name', 'Field'],
757
+
['leave', 'Name', 'name', 'Field'],
758
+
['leave', 'Field', 0, undefined],
759
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
760
+
['leave', 'Field', 1, undefined],
761
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
762
+
['leave', 'Field', 0, undefined],
763
+
['leave', 'SelectionSet', 'selectionSet', 'Field'],
764
+
['leave', 'Field', 0, undefined],
765
+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
766
+
['leave', 'OperationDefinition', 2, undefined],
767
+
['enter', 'FragmentDefinition', 3, undefined],
768
+
['enter', 'Name', 'name', 'FragmentDefinition'],
769
+
['leave', 'Name', 'name', 'FragmentDefinition'],
770
+
['enter', 'NamedType', 'typeCondition', 'FragmentDefinition'],
771
+
['enter', 'Name', 'name', 'NamedType'],
772
+
['leave', 'Name', 'name', 'NamedType'],
773
+
['leave', 'NamedType', 'typeCondition', 'FragmentDefinition'],
774
+
['enter', 'Directive', 0, undefined],
775
+
['enter', 'Name', 'name', 'Directive'],
776
+
['leave', 'Name', 'name', 'Directive'],
777
+
['leave', 'Directive', 0, undefined],
778
+
['enter', 'SelectionSet', 'selectionSet', 'FragmentDefinition'],
779
+
['enter', 'Field', 0, undefined],
780
+
['enter', 'Name', 'name', 'Field'],
781
+
['leave', 'Name', 'name', 'Field'],
782
+
['enter', 'Argument', 0, undefined],
783
+
['enter', 'Name', 'name', 'Argument'],
784
+
['leave', 'Name', 'name', 'Argument'],
785
+
['enter', 'Variable', 'value', 'Argument'],
786
+
['enter', 'Name', 'name', 'Variable'],
787
+
['leave', 'Name', 'name', 'Variable'],
788
+
['leave', 'Variable', 'value', 'Argument'],
789
+
['leave', 'Argument', 0, undefined],
790
+
['enter', 'Argument', 1, undefined],
791
+
['enter', 'Name', 'name', 'Argument'],
792
+
['leave', 'Name', 'name', 'Argument'],
793
+
['enter', 'Variable', 'value', 'Argument'],
794
+
['enter', 'Name', 'name', 'Variable'],
795
+
['leave', 'Name', 'name', 'Variable'],
796
+
['leave', 'Variable', 'value', 'Argument'],
797
+
['leave', 'Argument', 1, undefined],
798
+
['enter', 'Argument', 2, undefined],
799
+
['enter', 'Name', 'name', 'Argument'],
800
+
['leave', 'Name', 'name', 'Argument'],
801
+
['enter', 'ObjectValue', 'value', 'Argument'],
802
+
['enter', 'ObjectField', 0, undefined],
803
+
['enter', 'Name', 'name', 'ObjectField'],
804
+
['leave', 'Name', 'name', 'ObjectField'],
805
+
['enter', 'StringValue', 'value', 'ObjectField'],
806
+
['leave', 'StringValue', 'value', 'ObjectField'],
807
+
['leave', 'ObjectField', 0, undefined],
808
+
['enter', 'ObjectField', 1, undefined],
809
+
['enter', 'Name', 'name', 'ObjectField'],
810
+
['leave', 'Name', 'name', 'ObjectField'],
811
+
['enter', 'StringValue', 'value', 'ObjectField'],
812
+
['leave', 'StringValue', 'value', 'ObjectField'],
813
+
['leave', 'ObjectField', 1, undefined],
814
+
['leave', 'ObjectValue', 'value', 'Argument'],
815
+
['leave', 'Argument', 2, undefined],
816
+
['leave', 'Field', 0, undefined],
817
+
['leave', 'SelectionSet', 'selectionSet', 'FragmentDefinition'],
818
+
['leave', 'FragmentDefinition', 3, undefined],
819
+
['enter', 'OperationDefinition', 4, undefined],
820
+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
821
+
['enter', 'Field', 0, undefined],
822
+
['enter', 'Name', 'name', 'Field'],
823
+
['leave', 'Name', 'name', 'Field'],
824
+
['enter', 'Argument', 0, undefined],
825
+
['enter', 'Name', 'name', 'Argument'],
826
+
['leave', 'Name', 'name', 'Argument'],
827
+
['enter', 'BooleanValue', 'value', 'Argument'],
828
+
['leave', 'BooleanValue', 'value', 'Argument'],
829
+
['leave', 'Argument', 0, undefined],
830
+
['enter', 'Argument', 1, undefined],
831
+
['enter', 'Name', 'name', 'Argument'],
832
+
['leave', 'Name', 'name', 'Argument'],
833
+
['enter', 'BooleanValue', 'value', 'Argument'],
834
+
['leave', 'BooleanValue', 'value', 'Argument'],
835
+
['leave', 'Argument', 1, undefined],
836
+
['enter', 'Argument', 2, undefined],
837
+
['enter', 'Name', 'name', 'Argument'],
838
+
['leave', 'Name', 'name', 'Argument'],
839
+
['enter', 'NullValue', 'value', 'Argument'],
840
+
['leave', 'NullValue', 'value', 'Argument'],
841
+
['leave', 'Argument', 2, undefined],
842
+
['leave', 'Field', 0, undefined],
843
+
['enter', 'Field', 1, undefined],
844
+
['enter', 'Name', 'name', 'Field'],
845
+
['leave', 'Name', 'name', 'Field'],
846
+
['leave', 'Field', 1, undefined],
847
+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
848
+
['leave', 'OperationDefinition', 4, undefined],
849
+
['enter', 'OperationDefinition', 5, undefined],
850
+
['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
851
+
['enter', 'Field', 0, undefined],
852
+
['enter', 'Name', 'name', 'Field'],
853
+
['leave', 'Name', 'name', 'Field'],
854
+
['leave', 'Field', 0, undefined],
855
+
['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],
856
+
['leave', 'OperationDefinition', 5, undefined],
857
+
['leave', 'Document', undefined, undefined],
861
+
// TODO: Verify discrepancies
862
+
describe('visitInParallel', () => {
863
+
// Note: nearly identical to the above test of the same test but
864
+
// using visitInParallel.
865
+
it('allows skipping a sub-tree', () => {
866
+
const visited: Array<any> = [];
868
+
const ast = parse('{ a, b { x }, c }');
874
+
checkVisitorFnArgs(ast, arguments);
875
+
visited.push(['enter', node.kind, getValue(node)]);
876
+
if (node.kind === 'Field' && node.name.value === 'b') {
882
+
checkVisitorFnArgs(ast, arguments);
883
+
visited.push(['leave', node.kind, getValue(node)]);
889
+
expect(visited).toEqual([
890
+
['enter', 'Document', undefined],
891
+
['enter', 'OperationDefinition', undefined],
892
+
['enter', 'SelectionSet', undefined],
893
+
['enter', 'Field', undefined],
894
+
['enter', 'Name', 'a'],
895
+
['leave', 'Name', 'a'],
896
+
['leave', 'Field', undefined],
897
+
['enter', 'Field', undefined],
898
+
['enter', 'Field', undefined],
899
+
['enter', 'Name', 'c'],
900
+
['leave', 'Name', 'c'],
901
+
['leave', 'Field', undefined],
902
+
['leave', 'SelectionSet', undefined],
903
+
['leave', 'OperationDefinition', undefined],
904
+
['leave', 'Document', undefined],
908
+
it('allows skipping different sub-trees', () => {
909
+
const visited: Array<any> = [];
911
+
const ast = parse('{ a { x }, b { y} }');
917
+
checkVisitorFnArgs(ast, arguments);
918
+
visited.push(['no-a', 'enter', node.kind, getValue(node)]);
919
+
if (node.kind === 'Field' && node.name.value === 'a') {
924
+
checkVisitorFnArgs(ast, arguments);
925
+
visited.push(['no-a', 'leave', node.kind, getValue(node)]);
930
+
checkVisitorFnArgs(ast, arguments);
931
+
visited.push(['no-b', 'enter', node.kind, getValue(node)]);
932
+
if (node.kind === 'Field' && node.name.value === 'b') {
937
+
checkVisitorFnArgs(ast, arguments);
938
+
visited.push(['no-b', 'leave', node.kind, getValue(node)]);
944
+
expect(visited).toEqual([
945
+
['no-a', 'enter', 'Document', undefined],
946
+
['no-b', 'enter', 'Document', undefined],
947
+
['no-a', 'enter', 'OperationDefinition', undefined],
948
+
['no-b', 'enter', 'OperationDefinition', undefined],
949
+
['no-a', 'enter', 'SelectionSet', undefined],
950
+
['no-b', 'enter', 'SelectionSet', undefined],
951
+
['no-a', 'enter', 'Field', undefined],
952
+
['no-b', 'enter', 'Field', undefined],
953
+
['no-b', 'enter', 'Name', 'a'],
954
+
['no-b', 'leave', 'Name', 'a'],
955
+
['no-b', 'enter', 'SelectionSet', undefined],
956
+
['no-b', 'enter', 'Field', undefined],
957
+
['no-b', 'enter', 'Name', 'x'],
958
+
['no-b', 'leave', 'Name', 'x'],
959
+
['no-b', 'leave', 'Field', undefined],
960
+
['no-b', 'leave', 'SelectionSet', undefined],
961
+
['no-b', 'leave', 'Field', undefined],
962
+
['no-a', 'enter', 'Field', undefined],
963
+
['no-b', 'enter', 'Field', undefined],
964
+
['no-a', 'enter', 'Name', 'b'],
965
+
['no-a', 'leave', 'Name', 'b'],
966
+
['no-a', 'enter', 'SelectionSet', undefined],
967
+
['no-a', 'enter', 'Field', undefined],
968
+
['no-a', 'enter', 'Name', 'y'],
969
+
['no-a', 'leave', 'Name', 'y'],
970
+
['no-a', 'leave', 'Field', undefined],
971
+
['no-a', 'leave', 'SelectionSet', undefined],
972
+
['no-a', 'leave', 'Field', undefined],
973
+
['no-a', 'leave', 'SelectionSet', undefined],
974
+
['no-b', 'leave', 'SelectionSet', undefined],
975
+
['no-a', 'leave', 'OperationDefinition', undefined],
976
+
['no-b', 'leave', 'OperationDefinition', undefined],
977
+
['no-a', 'leave', 'Document', undefined],
978
+
['no-b', 'leave', 'Document', undefined],
982
+
// Note: nearly identical to the above test of the same test but
983
+
// using visitInParallel.
984
+
it('allows early exit while visiting', () => {
985
+
const visited: Array<any> = [];
987
+
const ast = parse('{ a, b { x }, c }');
993
+
checkVisitorFnArgs(ast, arguments);
994
+
visited.push(['enter', node.kind, getValue(node)]);
995
+
if (node.kind === 'Name' && node.value === 'x') {
1000
+
checkVisitorFnArgs(ast, arguments);
1001
+
visited.push(['leave', node.kind, getValue(node)]);
1007
+
expect(visited).toEqual([
1008
+
['enter', 'Document', undefined],
1009
+
['enter', 'OperationDefinition', undefined],
1010
+
['enter', 'SelectionSet', undefined],
1011
+
['enter', 'Field', undefined],
1012
+
['enter', 'Name', 'a'],
1013
+
['leave', 'Name', 'a'],
1014
+
['leave', 'Field', undefined],
1015
+
['enter', 'Field', undefined],
1016
+
['enter', 'Name', 'b'],
1017
+
['leave', 'Name', 'b'],
1018
+
['enter', 'SelectionSet', undefined],
1019
+
['enter', 'Field', undefined],
1020
+
['enter', 'Name', 'x'],
1024
+
it('allows early exit from different points', () => {
1025
+
const visited: Array<any> = [];
1027
+
const ast = parse('{ a { y }, b { x } }');
1033
+
checkVisitorFnArgs(ast, arguments);
1034
+
visited.push(['break-a', 'enter', node.kind, getValue(node)]);
1035
+
if (node.kind === 'Name' && node.value === 'a') {
1039
+
// istanbul ignore next (Never called and used as a placeholder)
1041
+
expect.fail('Should not be called');
1046
+
checkVisitorFnArgs(ast, arguments);
1047
+
visited.push(['break-b', 'enter', node.kind, getValue(node)]);
1048
+
if (node.kind === 'Name' && node.value === 'b') {
1053
+
checkVisitorFnArgs(ast, arguments);
1054
+
visited.push(['break-b', 'leave', node.kind, getValue(node)]);
1060
+
expect(visited).toEqual([
1061
+
['break-a', 'enter', 'Document', undefined],
1062
+
['break-b', 'enter', 'Document', undefined],
1063
+
['break-a', 'enter', 'OperationDefinition', undefined],
1064
+
['break-b', 'enter', 'OperationDefinition', undefined],
1065
+
['break-a', 'enter', 'SelectionSet', undefined],
1066
+
['break-b', 'enter', 'SelectionSet', undefined],
1067
+
['break-a', 'enter', 'Field', undefined],
1068
+
['break-b', 'enter', 'Field', undefined],
1069
+
['break-a', 'enter', 'Name', 'a'],
1070
+
['break-b', 'enter', 'Name', 'a'],
1071
+
['break-b', 'leave', 'Name', 'a'],
1072
+
['break-b', 'enter', 'SelectionSet', undefined],
1073
+
['break-b', 'enter', 'Field', undefined],
1074
+
['break-b', 'enter', 'Name', 'y'],
1075
+
['break-b', 'leave', 'Name', 'y'],
1076
+
['break-b', 'leave', 'Field', undefined],
1077
+
['break-b', 'leave', 'SelectionSet', undefined],
1078
+
['break-b', 'leave', 'Field', undefined],
1079
+
['break-b', 'enter', 'Field', undefined],
1080
+
['break-b', 'enter', 'Name', 'b'],
1084
+
// Note: nearly identical to the above test of the same test but
1085
+
// using visitInParallel.
1086
+
it('allows early exit while leaving', () => {
1087
+
const visited: Array<any> = [];
1089
+
const ast = parse('{ a, b { x }, c }');
1095
+
checkVisitorFnArgs(ast, arguments);
1096
+
visited.push(['enter', node.kind, getValue(node)]);
1099
+
checkVisitorFnArgs(ast, arguments);
1100
+
visited.push(['leave', node.kind, getValue(node)]);
1101
+
if (node.kind === 'Name' && node.value === 'x') {
1109
+
expect(visited).toEqual([
1110
+
['enter', 'Document', undefined],
1111
+
['enter', 'OperationDefinition', undefined],
1112
+
['enter', 'SelectionSet', undefined],
1113
+
['enter', 'Field', undefined],
1114
+
['enter', 'Name', 'a'],
1115
+
['leave', 'Name', 'a'],
1116
+
['leave', 'Field', undefined],
1117
+
['enter', 'Field', undefined],
1118
+
['enter', 'Name', 'b'],
1119
+
['leave', 'Name', 'b'],
1120
+
['enter', 'SelectionSet', undefined],
1121
+
['enter', 'Field', undefined],
1122
+
['enter', 'Name', 'x'],
1123
+
['leave', 'Name', 'x'],
1127
+
it('allows early exit from leaving different points', () => {
1128
+
const visited: Array<any> = [];
1130
+
const ast = parse('{ a { y }, b { x } }');
1136
+
checkVisitorFnArgs(ast, arguments);
1137
+
visited.push(['break-a', 'enter', node.kind, getValue(node)]);
1140
+
checkVisitorFnArgs(ast, arguments);
1141
+
visited.push(['break-a', 'leave', node.kind, getValue(node)]);
1142
+
if (node.kind === 'Field' && node.name.value === 'a') {
1149
+
checkVisitorFnArgs(ast, arguments);
1150
+
visited.push(['break-b', 'enter', node.kind, getValue(node)]);
1153
+
checkVisitorFnArgs(ast, arguments);
1154
+
visited.push(['break-b', 'leave', node.kind, getValue(node)]);
1155
+
if (node.kind === 'Field' && node.name.value === 'b') {
1163
+
expect(visited).toEqual([
1164
+
['break-a', 'enter', 'Document', undefined],
1165
+
['break-b', 'enter', 'Document', undefined],
1166
+
['break-a', 'enter', 'OperationDefinition', undefined],
1167
+
['break-b', 'enter', 'OperationDefinition', undefined],
1168
+
['break-a', 'enter', 'SelectionSet', undefined],
1169
+
['break-b', 'enter', 'SelectionSet', undefined],
1170
+
['break-a', 'enter', 'Field', undefined],
1171
+
['break-b', 'enter', 'Field', undefined],
1172
+
['break-a', 'enter', 'Name', 'a'],
1173
+
['break-b', 'enter', 'Name', 'a'],
1174
+
['break-a', 'leave', 'Name', 'a'],
1175
+
['break-b', 'leave', 'Name', 'a'],
1176
+
['break-a', 'enter', 'SelectionSet', undefined],
1177
+
['break-b', 'enter', 'SelectionSet', undefined],
1178
+
['break-a', 'enter', 'Field', undefined],
1179
+
['break-b', 'enter', 'Field', undefined],
1180
+
['break-a', 'enter', 'Name', 'y'],
1181
+
['break-b', 'enter', 'Name', 'y'],
1182
+
['break-a', 'leave', 'Name', 'y'],
1183
+
['break-b', 'leave', 'Name', 'y'],
1184
+
['break-a', 'leave', 'Field', undefined],
1185
+
['break-b', 'leave', 'Field', undefined],
1186
+
['break-a', 'leave', 'SelectionSet', undefined],
1187
+
['break-b', 'leave', 'SelectionSet', undefined],
1188
+
['break-a', 'leave', 'Field', undefined],
1189
+
['break-b', 'leave', 'Field', undefined],
1190
+
['break-b', 'enter', 'Field', undefined],
1191
+
['break-b', 'enter', 'Name', 'b'],
1192
+
['break-b', 'leave', 'Name', 'b'],
1193
+
['break-b', 'enter', 'SelectionSet', undefined],
1194
+
['break-b', 'enter', 'Field', undefined],
1195
+
['break-b', 'enter', 'Name', 'x'],
1196
+
['break-b', 'leave', 'Name', 'x'],
1197
+
['break-b', 'leave', 'Field', undefined],
1198
+
['break-b', 'leave', 'SelectionSet', undefined],
1199
+
['break-b', 'leave', 'Field', undefined],
1203
+
it('allows for editing on enter', () => {
1204
+
const visited: Array<any> = [];
1206
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
1207
+
const editedAST = visit(
1212
+
checkVisitorFnArgs(ast, arguments);
1213
+
if (node.kind === 'Field' && node.name.value === 'b') {
1220
+
checkVisitorFnArgs(ast, arguments);
1221
+
visited.push(['enter', node.kind, getValue(node)]);
1224
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
1225
+
visited.push(['leave', node.kind, getValue(node)]);
1231
+
expect(ast).toEqual(
1232
+
parse('{ a, b, c { a, b, c } }', { noLocation: true })
1235
+
expect(editedAST).toEqual(
1236
+
parse('{ a, c { a, c } }', { noLocation: true })
1239
+
expect(visited).toEqual([
1240
+
['enter', 'Document', undefined],
1241
+
['enter', 'OperationDefinition', undefined],
1242
+
['enter', 'SelectionSet', undefined],
1243
+
['enter', 'Field', undefined],
1244
+
['enter', 'Name', 'a'],
1245
+
['leave', 'Name', 'a'],
1246
+
['leave', 'Field', undefined],
1247
+
['enter', 'Field', undefined],
1248
+
['enter', 'Name', 'c'],
1249
+
['leave', 'Name', 'c'],
1250
+
['enter', 'SelectionSet', undefined],
1251
+
['enter', 'Field', undefined],
1252
+
['enter', 'Name', 'a'],
1253
+
['leave', 'Name', 'a'],
1254
+
['leave', 'Field', undefined],
1255
+
['enter', 'Field', undefined],
1256
+
['enter', 'Name', 'c'],
1257
+
['leave', 'Name', 'c'],
1258
+
['leave', 'Field', undefined],
1259
+
['leave', 'SelectionSet', undefined],
1260
+
['leave', 'Field', undefined],
1261
+
['leave', 'SelectionSet', undefined],
1262
+
['leave', 'OperationDefinition', undefined],
1263
+
['leave', 'Document', undefined],
1267
+
it('allows for editing on leave', () => {
1268
+
const visited: Array<any> = [];
1270
+
const ast = parse('{ a, b, c { a, b, c } }', { noLocation: true });
1271
+
const editedAST = visit(
1276
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
1277
+
if (node.kind === 'Field' && node.name.value === 'b') {
1284
+
checkVisitorFnArgs(ast, arguments);
1285
+
visited.push(['enter', node.kind, getValue(node)]);
1288
+
checkVisitorFnArgs(ast, arguments, /* isEdited */ true);
1289
+
visited.push(['leave', node.kind, getValue(node)]);
1295
+
expect(ast).toEqual(
1296
+
parse('{ a, b, c { a, b, c } }', { noLocation: true })
1299
+
expect(editedAST).toEqual(
1300
+
parse('{ a, c { a, c } }', { noLocation: true })
1303
+
expect(visited).toEqual([
1304
+
['enter', 'Document', undefined],
1305
+
['enter', 'OperationDefinition', undefined],
1306
+
['enter', 'SelectionSet', undefined],
1307
+
['enter', 'Field', undefined],
1308
+
['enter', 'Name', 'a'],
1309
+
['leave', 'Name', 'a'],
1310
+
['leave', 'Field', undefined],
1311
+
['enter', 'Field', undefined],
1312
+
['enter', 'Name', 'b'],
1313
+
['leave', 'Name', 'b'],
1314
+
['enter', 'Field', undefined],
1315
+
['enter', 'Name', 'c'],
1316
+
['leave', 'Name', 'c'],
1317
+
['enter', 'SelectionSet', undefined],
1318
+
['enter', 'Field', undefined],
1319
+
['enter', 'Name', 'a'],
1320
+
['leave', 'Name', 'a'],
1321
+
['leave', 'Field', undefined],
1322
+
['enter', 'Field', undefined],
1323
+
['enter', 'Name', 'b'],
1324
+
['leave', 'Name', 'b'],
1325
+
['enter', 'Field', undefined],
1326
+
['enter', 'Name', 'c'],
1327
+
['leave', 'Name', 'c'],
1328
+
['leave', 'Field', undefined],
1329
+
['leave', 'SelectionSet', undefined],
1330
+
['leave', 'Field', undefined],
1331
+
['leave', 'SelectionSet', undefined],
1332
+
['leave', 'OperationDefinition', undefined],
1333
+
['leave', 'Document', undefined],