/
simple-traverse.ts
58 lines (48 loc) · 1.44 KB
/
simple-traverse.ts
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
import { TSESTree } from '@typescript-eslint/typescript-estree';
import { visitorKeys } from './visitor-keys';
function isValidNode(x: any): x is TSESTree.Node {
return x !== null && typeof x === 'object' && typeof x.type === 'string';
}
function getVisitorKeysForNode(
allVisitorKeys: typeof visitorKeys,
node: TSESTree.Node,
): readonly string[] {
const keys = allVisitorKeys[node.type];
return keys || [];
}
interface SimpleTraverseOptions {
enter: (node: TSESTree.Node, parent: TSESTree.Node | undefined) => void;
}
class SimpleTraverser {
private allVisitorKeys = visitorKeys;
private enter: SimpleTraverseOptions['enter'];
constructor({ enter }: SimpleTraverseOptions) {
this.enter = enter;
}
traverse(node: unknown, parent: TSESTree.Node | undefined) {
if (!isValidNode(node)) {
return;
}
this.enter(node, parent);
const keys = getVisitorKeysForNode(this.allVisitorKeys, node);
if (keys.length < 1) {
return;
}
for (const key of keys) {
const childOrChildren = node[key as keyof typeof node];
if (Array.isArray(childOrChildren)) {
for (const child of childOrChildren) {
this.traverse(child, node);
}
} else {
this.traverse(childOrChildren, node);
}
}
}
}
export function simpleTraverse(
startingNode: TSESTree.Node,
options: SimpleTraverseOptions,
) {
new SimpleTraverser(options).traverse(startingNode, undefined);
}