Skip to content

Commit 0091421

Browse files
Bring visitorKeys back (#3250)
Co-authored-by: Ivan Goncharov <ivan.goncharov.ua@gmail.com>
1 parent 505b4f8 commit 0091421

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ export type {
234234
/** Visitor utilities */
235235
ASTVisitor,
236236
ASTVisitFn,
237+
ASTVisitorKeyMap,
237238
/** AST nodes */
238239
ASTNode,
239240
ASTKindToNode,

src/language/__tests__/visitor-test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { describe, it } from 'mocha';
44
import { kitchenSinkQuery } from '../../__testUtils__/kitchenSinkQuery';
55

66
import type { ASTNode, SelectionSetNode } from '../ast';
7+
import type { ASTVisitorKeyMap, ASTVisitor } from '../visitor';
78
import { isNode } from '../ast';
89
import { Kind } from '../kinds';
910
import { parse } from '../parser';
@@ -462,6 +463,41 @@ describe('Visitor', () => {
462463
]);
463464
});
464465

466+
it('visits only the specified `Kind` in visitorKeyMap', () => {
467+
const visited: Array<any> = [];
468+
469+
const visitorKeyMap: ASTVisitorKeyMap = {
470+
Document: ['definitions'],
471+
OperationDefinition: ['name'],
472+
};
473+
474+
const visitor: ASTVisitor = {
475+
enter(node) {
476+
visited.push(['enter', node.kind, getValue(node)]);
477+
},
478+
leave(node) {
479+
visited.push(['leave', node.kind, getValue(node)]);
480+
},
481+
};
482+
483+
const exampleDocumentAST = parse(`
484+
query ExampleOperation {
485+
someField
486+
}
487+
`);
488+
489+
visit(exampleDocumentAST, visitor, visitorKeyMap);
490+
491+
expect(visited).to.deep.equal([
492+
['enter', 'Document', undefined],
493+
['enter', 'OperationDefinition', undefined],
494+
['enter', 'Name', 'ExampleOperation'],
495+
['leave', 'Name', 'ExampleOperation'],
496+
['leave', 'OperationDefinition', undefined],
497+
['leave', 'Document', undefined],
498+
]);
499+
});
500+
465501
it('Legacy: visits variables defined in fragments', () => {
466502
const ast = parse('fragment a($v: Boolean = false) on t { f }', {
467503
noLocation: true,

src/language/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export type { ParseOptions } from './parser';
1919
export { print } from './printer';
2020

2121
export { visit, visitInParallel, getVisitFn, BREAK } from './visitor';
22-
export type { ASTVisitor, ASTVisitFn } from './visitor';
22+
export type { ASTVisitor, ASTVisitFn, ASTVisitorKeyMap } from './visitor';
2323

2424
export { Location, Token } from './ast';
2525
export type {

src/language/visitor.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,14 @@ type ReducedField<T, R> = T extends null | undefined
7676
? ReadonlyArray<R>
7777
: R;
7878

79-
const QueryDocumentKeys = {
80-
Name: [],
79+
/**
80+
* A KeyMap describes each the traversable properties of each kind of node.
81+
*/
82+
export type ASTVisitorKeyMap = {
83+
[P in keyof ASTKindToNode]?: ReadonlyArray<keyof ASTKindToNode[P]>;
84+
};
8185

86+
export const QueryDocumentKeys: ASTVisitorKeyMap = {
8287
Document: ['definitions'],
8388
OperationDefinition: [
8489
'name',
@@ -103,12 +108,6 @@ const QueryDocumentKeys = {
103108
'selectionSet',
104109
],
105110

106-
IntValue: [],
107-
FloatValue: [],
108-
StringValue: [],
109-
BooleanValue: [],
110-
NullValue: [],
111-
EnumValue: [],
112111
ListValue: ['values'],
113112
ObjectValue: ['fields'],
114113
ObjectField: ['name', 'value'],
@@ -242,11 +241,20 @@ export const BREAK: unknown = Object.freeze({});
242241
* })
243242
* ```
244243
*/
245-
export function visit<N extends ASTNode>(root: N, visitor: ASTVisitor): N;
246-
export function visit<R>(root: ASTNode, visitor: ASTReducer<R>): R;
244+
export function visit<N extends ASTNode>(
245+
root: N,
246+
visitor: ASTVisitor,
247+
visitorKeys?: ASTVisitorKeyMap,
248+
): N;
249+
export function visit<R>(
250+
root: ASTNode,
251+
visitor: ASTReducer<R>,
252+
visitorKeys?: ASTVisitorKeyMap,
253+
): R;
247254
export function visit(
248255
root: ASTNode,
249256
visitor: ASTVisitor | ASTReducer<any>,
257+
visitorKeys: ASTVisitorKeyMap = QueryDocumentKeys,
250258
): any {
251259
/* eslint-disable no-undef-init */
252260
let stack: any = undefined;
@@ -346,7 +354,7 @@ export function visit(
346354
} else {
347355
stack = { inArray, index, keys, edits, prev: stack };
348356
inArray = Array.isArray(node);
349-
keys = inArray ? node : (QueryDocumentKeys as any)[node.kind] ?? [];
357+
keys = inArray ? node : (visitorKeys as any)[node.kind] ?? [];
350358
index = -1;
351359
edits = [];
352360
if (parent) {

0 commit comments

Comments
 (0)