1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 | 2x
2x
2x
2x
1605x
304x
487x
1605x
1605x
304x
814x
1605x
1605x
1x
1604x
303x
4298x
4298x
2693x
5370x
791x
791x
487x
1156x
303x
1115x
1115x
426x
18x
303x
11x
4x
3x
7x
11x
313x
313x
21x
313x
| import * as ts from 'typescript';
import {
DefKind,
IgnoredKinds,
ignoredKindsMap,
Kind,
NodeOrNodes,
Visitor,
} from './types';
import { defs } from './utils';
export default function visitNode(
node: ts.Node,
visitor: Visitor,
kind: DefKind,
iterateBase: boolean,
) {
if (iterateBase) {
for (const key of resolveUnion(kind)) {
visitNode(node, visitor, key, false);
}
}
const baseKinds = resolveBase(kind);
if (iterateBase) {
for (const key of baseKinds) {
visitNode(node, visitor, key, false);
}
}
const visitorFunc = visitor[kind] || visitor.Default;
if (visitorFunc(node, kind) === false) {
return;
}
if (iterateBase) {
visitChildren(visitor, resolveChildren(node, baseKinds));
}
}
function resolveBase(kind: DefKind): DefKind[] {
const base = defs[kind].base;
return base
.reduce((r, d) => r.concat(resolveBase(d)), [...base] as DefKind[])
.filter((o, i, a) => a.indexOf(o) === i);
}
function resolveUnion(kind: DefKind): DefKind[] {
const union = defs[kind].union || [];
return union
.reduce((r, d) => r.concat(resolveUnion(d)), [...union] as DefKind[])
.filter((o, i, a) => a.indexOf(o) === i);
}
function resolveChildren(node: ts.Node, baseKinds: DefKind[]): NodeOrNodes[] {
return [...baseKinds, getKind(node)]
.map(k => defs[k].getChildren)
.reduce((r, w) => (w ? r.concat(w(node)) : r), [] as NodeOrNodes[])
.filter(o => o !== undefined)
.filter((o, i, a) => a.indexOf(o) === i);
}
function visitChildren(visitor: Visitor, items: NodeOrNodes[]) {
for (const item of items) {
if (isArray(item)) {
for (const child of item) {
visitNode(child, visitor, getKind(child), true);
}
} else {
visitNode(item as ts.Node, visitor, getKind(item as ts.Node), true);
}
}
}
function isArray(node: NodeOrNodes): node is ReadonlyArray<ts.Node> {
return Array.isArray(node);
}
function getKind(node: ts.Node): Kind {
let value = ts.SyntaxKind[node.kind];
if (IgnoredKinds.hasOwnProperty(value)) {
value = ignoredKindsMap[value];
}
return value as Kind;
}
|