-
Notifications
You must be signed in to change notification settings - Fork 414
/
Visitors.ts
85 lines (72 loc) · 2.22 KB
/
Visitors.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
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
import { types as t } from '@babel/core';
import peek from '../../utils/peek';
import { warn } from '../../utils/logger';
import GraphBuilderState from './GraphBuilderState';
import identifierHandlers from './identifierHandlers';
import { Visitor, Visitors } from './types';
import { visitors as core } from './langs/core';
const visitors: Visitors = {
Identifier<TParent extends t.Node>(
this: GraphBuilderState,
node: t.Identifier,
parent: TParent | null,
parentKey: t.VisitorKeys[TParent['type']] | null,
listIdx: number | null = null
) {
if (!parent || !parentKey) {
return;
}
const handler = identifierHandlers[`${parent.type}:${parentKey}`];
if (typeof handler === 'function') {
handler(this, node, parent, parentKey, listIdx);
return;
}
if (handler === 'keep') {
return;
}
if (handler === 'declare') {
const kindOfDeclaration = this.meta.get('kind-of-declaration');
this.scope.declare(node, kindOfDeclaration === 'var', null);
return;
}
if (handler === 'refer') {
const declaration = this.scope.addReference(node);
// Let's check that it's not a global variable
if (declaration) {
// usage of a variable depends on its declaration
this.graph.addEdge(node, declaration);
const context = peek(this.context);
if (context === 'lval') {
// This is an identifier in the left side of an assignment expression and a variable value depends on that.
this.graph.addEdge(declaration, node);
}
}
return;
}
/*
* There is an unhandled identifier.
* This case should be added to ./identifierHandlers.ts
*/
warn(
'evaluator:shaker',
'Unhandled identifier',
node.name,
parent.type,
parentKey,
listIdx
);
},
...core,
};
export function getVisitors<TNode extends t.Node>(
node: TNode
): Visitor<TNode>[] {
const aliases: Array<keyof t.Aliases> = t.ALIAS_KEYS[node.type] || [];
const aliasVisitors = aliases
.map((type) => visitors[type])
.filter((i) => i) as Visitor<TNode>[];
return [...aliasVisitors, visitors[node.type] as Visitor<TNode>].filter(
(v) => v
);
}
export default visitors;