-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
ExportVisitor.ts
82 lines (72 loc) · 2.45 KB
/
ExportVisitor.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
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/types';
import { Referencer } from './Referencer';
import { Visitor } from './Visitor';
type ExportNode =
| TSESTree.ExportAllDeclaration
| TSESTree.ExportDefaultDeclaration
| TSESTree.ExportNamedDeclaration;
class ExportVisitor extends Visitor {
readonly #referencer: Referencer;
readonly #exportNode: ExportNode;
constructor(node: ExportNode, referencer: Referencer) {
super(referencer);
this.#exportNode = node;
this.#referencer = referencer;
}
static visit(referencer: Referencer, node: ExportNode): void {
const exportReferencer = new ExportVisitor(node, referencer);
exportReferencer.visit(node);
}
protected Identifier(node: TSESTree.Identifier): void {
if (this.#exportNode.exportKind === 'type') {
// export type { T };
// type exports can only reference types
this.#referencer.currentScope().referenceType(node);
} else {
this.#referencer.currentScope().referenceDualValueType(node);
}
}
protected ExportDefaultDeclaration(
node: TSESTree.ExportDefaultDeclaration,
): void {
if (node.declaration.type === AST_NODE_TYPES.Identifier) {
// export default A;
// this could be a type or a variable
this.visit(node.declaration);
} else {
// export const a = 1;
// export something();
// etc
// these not included in the scope of this visitor as they are all guaranteed to be values or declare variables
}
}
protected ExportNamedDeclaration(
node: TSESTree.ExportNamedDeclaration,
): void {
if (node.source) {
// export ... from 'foo';
// these are external identifiers so there shouldn't be references or defs
return;
}
if (!node.declaration) {
// export { x };
this.visitChildren(node);
} else {
// export const x = 1;
// this is not included in the scope of this visitor as it creates a variable
}
}
protected ExportSpecifier(node: TSESTree.ExportSpecifier): void {
if (node.exportKind === 'type') {
// export { type T };
// type exports can only reference types
//
// we can't let this fall through to the Identifier selector because the exportKind is on this node
// and we don't have access to the `.parent` during scope analysis
this.#referencer.currentScope().referenceType(node.local);
} else {
this.visit(node.local);
}
}
}
export { ExportVisitor };