/
ChildScope.ts
114 lines (103 loc) · 3.66 KB
/
ChildScope.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import type { InternalModuleFormat } from '../../rollup/types';
import { getSafeName } from '../../utils/safeName';
import type ImportExpression from '../nodes/ImportExpression';
import type { ExpressionEntity } from '../nodes/shared/Expression';
import type Variable from '../variables/Variable';
import Scope from './Scope';
export default class ChildScope extends Scope {
readonly accessedOutsideVariables = new Map<string, Variable>();
parent: Scope;
private declare accessedDynamicImports?: Set<ImportExpression>;
constructor(parent: Scope) {
super();
this.parent = parent;
parent.children.push(this);
}
addAccessedDynamicImport(importExpression: ImportExpression): void {
(this.accessedDynamicImports || (this.accessedDynamicImports = new Set())).add(
importExpression
);
if (this.parent instanceof ChildScope) {
this.parent.addAccessedDynamicImport(importExpression);
}
}
addAccessedGlobals(
globals: readonly string[],
accessedGlobalsByScope: Map<ChildScope, Set<string>>
): void {
const accessedGlobals = accessedGlobalsByScope.get(this) || new Set();
for (const name of globals) {
accessedGlobals.add(name);
}
accessedGlobalsByScope.set(this, accessedGlobals);
if (this.parent instanceof ChildScope) {
this.parent.addAccessedGlobals(globals, accessedGlobalsByScope);
}
}
addNamespaceMemberAccess(name: string, variable: Variable): void {
this.accessedOutsideVariables.set(name, variable);
(this.parent as ChildScope).addNamespaceMemberAccess(name, variable);
}
addReturnExpression(expression: ExpressionEntity): void {
this.parent instanceof ChildScope && this.parent.addReturnExpression(expression);
}
addUsedOutsideNames(
usedNames: Set<string>,
format: InternalModuleFormat,
exportNamesByVariable: ReadonlyMap<Variable, readonly string[]>,
accessedGlobalsByScope: ReadonlyMap<ChildScope, ReadonlySet<string>>
): void {
for (const variable of this.accessedOutsideVariables.values()) {
if (variable.included) {
usedNames.add(variable.getBaseVariableName());
if (format === 'system' && exportNamesByVariable.has(variable)) {
usedNames.add('exports');
}
}
}
const accessedGlobals = accessedGlobalsByScope.get(this);
if (accessedGlobals) {
for (const name of accessedGlobals) {
usedNames.add(name);
}
}
}
contains(name: string): boolean {
return this.variables.has(name) || this.parent.contains(name);
}
deconflict(
format: InternalModuleFormat,
exportNamesByVariable: ReadonlyMap<Variable, readonly string[]>,
accessedGlobalsByScope: ReadonlyMap<ChildScope, ReadonlySet<string>>
): void {
const usedNames = new Set<string>();
this.addUsedOutsideNames(usedNames, format, exportNamesByVariable, accessedGlobalsByScope);
if (this.accessedDynamicImports) {
for (const importExpression of this.accessedDynamicImports) {
if (importExpression.inlineNamespace) {
usedNames.add(importExpression.inlineNamespace.getBaseVariableName());
}
}
}
for (const [name, variable] of this.variables) {
if (variable.included || variable.alwaysRendered) {
variable.setRenderNames(null, getSafeName(name, usedNames, variable.forbiddenNames));
}
}
for (const scope of this.children) {
scope.deconflict(format, exportNamesByVariable, accessedGlobalsByScope);
}
}
findLexicalBoundary(): ChildScope {
return (this.parent as ChildScope).findLexicalBoundary();
}
findVariable(name: string): Variable {
const knownVariable = this.variables.get(name) || this.accessedOutsideVariables.get(name);
if (knownVariable) {
return knownVariable;
}
const variable = this.parent.findVariable(name);
this.accessedOutsideVariables.set(name, variable);
return variable;
}
}