3
3
*
4
4
* This source code is licensed under the MIT license found in the
5
5
* LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ */
9
+
10
+ import type { ASTNode , ASTKindToNode } from './ast' ;
11
+ import type { TypeInfo } from '../utilities/TypeInfo' ;
12
+
13
+ /**
14
+ * A visitor is provided to visit, it contains the collection of
15
+ * relevant functions to be called during the visitor's traversal.
16
+ */
17
+ export type ASTVisitor = Visitor < ASTKindToNode > ;
18
+ export type Visitor < KindToNode , Nodes = $Values < KindToNode >> =
19
+ | EnterLeave <
20
+ | VisitFn < Nodes >
21
+ | ShapeMap < KindToNode , < Node > (Node) => VisitFn < Nodes , Node >> ,
22
+ >
23
+ | ShapeMap <
24
+ KindToNode ,
25
+ < Node > (Node) => VisitFn < Nodes , Node > | EnterLeave < VisitFn < Nodes , Node >> ,
26
+ > ;
27
+ type EnterLeave < T > = { | + enter ? : T , + leave ?: T | } ;
28
+ type ShapeMap < O , F > = $Shape < $ObjMap < O , F >> ;
29
+
30
+ /**
31
+ * A visitor is comprised of visit functions, which are called on each node
32
+ * during the visitor's traversal.
33
+ */
34
+ export type VisitFn < TAnyNode , TVisitedNode : TAnyNode = TAnyNode > = (
35
+ // The current node being visiting.
36
+ node : TVisitedNode ,
37
+ // The index or key to this node from the parent node or Array.
38
+ key : string | number | void ,
39
+ // The parent immediately above this node, which may be an Array.
40
+ parent : TAnyNode | $ReadOnlyArray < TAnyNode > | void ,
41
+ // The key path to get to this node from the root node.
42
+ path : $ReadOnlyArray < string | number > ,
43
+ // All nodes and Arrays visited before reaching this node.
44
+ // These correspond to array indices in `path`.
45
+ // Note: ancestors includes arrays which contain the visited node.
46
+ ancestors : $ReadOnlyArray < TAnyNode | $ReadOnlyArray < TAnyNode >> ,
47
+ ) => any ;
48
+
49
+ /**
50
+ * A KeyMap describes each the traversable properties of each kind of node.
6
51
*/
52
+ export type VisitorKeyMap < KindToNode > = $ObjMap <
53
+ KindToNode ,
54
+ < T > (T) => $ReadOnlyArray < $Keys < T >> ,
55
+ > ;
7
56
8
57
export const QueryDocumentKeys = {
9
58
Name : [ ] ,
@@ -172,24 +221,28 @@ export const BREAK = {};
172
221
* }
173
222
* })
174
223
*/
175
- export function visit ( root , visitor , keyMap ) {
176
- const visitorKeys = keyMap || QueryDocumentKeys ;
177
-
178
- let stack ;
224
+ export function visit (
225
+ root : ASTNode ,
226
+ visitor : Visitor < ASTKindToNode > ,
227
+ visitorKeys : VisitorKeyMap < ASTKindToNode > = QueryDocumentKeys ,
228
+ ) : mixed {
229
+ /* eslint-disable no-undef-init */
230
+ let stack : any = undefined ;
179
231
let inArray = Array . isArray ( root ) ;
180
- let keys = [ root ] ;
232
+ let keys : any = [ root ] ;
181
233
let index = - 1 ;
182
234
let edits = [ ] ;
183
- let parent ;
184
- const path = [ ] ;
235
+ let node : any = undefined ;
236
+ let key : any = undefined ;
237
+ let parent : any = undefined ;
238
+ const path : any = [ ] ;
185
239
const ancestors = [ ] ;
186
240
let newRoot = root ;
241
+ /* eslint-enable no-undef-init */
187
242
188
243
do {
189
244
index ++ ;
190
245
const isLeaving = index === keys . length ;
191
- let key ;
192
- let node ;
193
246
const isEdited = isLeaving && edits . length !== 0 ;
194
247
if ( isLeaving ) {
195
248
key = ancestors . length === 0 ? undefined : path [ path . length - 1 ] ;
@@ -209,7 +262,7 @@ export function visit(root, visitor, keyMap) {
209
262
}
210
263
let editOffset = 0 ;
211
264
for ( let ii = 0 ; ii < edits . length ; ii ++ ) {
212
- let editKey = edits [ ii ] [ 0 ] ;
265
+ let editKey : any = edits [ ii ] [ 0 ] ;
213
266
const editValue = edits [ ii ] [ 1 ] ;
214
267
if ( inArray ) {
215
268
editKey -= editOffset ;
@@ -296,8 +349,8 @@ export function visit(root, visitor, keyMap) {
296
349
return newRoot ;
297
350
}
298
351
299
- function isNode ( maybeNode ) {
300
- return maybeNode && typeof maybeNode . kind === 'string' ;
352
+ function isNode ( maybeNode ) : boolean % checks {
353
+ return Boolean ( maybeNode && typeof maybeNode . kind === 'string' ) ;
301
354
}
302
355
303
356
/**
@@ -306,7 +359,9 @@ function isNode(maybeNode) {
306
359
*
307
360
* If a prior visitor edits a node, no following visitors will see that node.
308
361
*/
309
- export function visitInParallel ( visitors ) {
362
+ export function visitInParallel (
363
+ visitors : Array < Visitor < ASTKindToNode >> ,
364
+ ) : Visitor < ASTKindToNode > {
310
365
const skipping = new Array ( visitors . length ) ;
311
366
312
367
return {
@@ -351,7 +406,10 @@ export function visitInParallel(visitors) {
351
406
* Creates a new visitor instance which maintains a provided TypeInfo instance
352
407
* along with visiting visitor.
353
408
*/
354
- export function visitWithTypeInfo ( typeInfo , visitor ) {
409
+ export function visitWithTypeInfo (
410
+ typeInfo : TypeInfo ,
411
+ visitor : Visitor < ASTKindToNode > ,
412
+ ) : Visitor < ASTKindToNode > {
355
413
return {
356
414
enter ( node ) {
357
415
typeInfo . enter ( node ) ;
@@ -383,7 +441,11 @@ export function visitWithTypeInfo(typeInfo, visitor) {
383
441
* Given a visitor instance, if it is leaving or not, and a node kind, return
384
442
* the function the visitor runtime should call.
385
443
*/
386
- export function getVisitFn ( visitor , kind , isLeaving ) {
444
+ export function getVisitFn (
445
+ visitor : Visitor < any > ,
446
+ kind : string ,
447
+ isLeaving : boolean ,
448
+ ) : ?VisitFn < any > {
387
449
const kindVisitor = visitor [ kind ] ;
388
450
if ( kindVisitor ) {
389
451
if ( ! isLeaving && typeof kindVisitor === 'function' ) {
0 commit comments