/
NamespaceVariable.ts
130 lines (110 loc) · 4.17 KB
/
NamespaceVariable.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import Module, { AstContext } from '../../Module';
import { RenderOptions } from '../../utils/renderHelpers';
import { RESERVED_NAMES } from '../../utils/reservedNames';
import { InclusionContext } from '../ExecutionContext';
import Identifier from '../nodes/Identifier';
import { UNKNOWN_PATH } from '../utils/PathTracker';
import ExternalVariable from './ExternalVariable';
import Variable from './Variable';
export default class NamespaceVariable extends Variable {
context: AstContext;
isNamespace!: true;
memberVariables: { [name: string]: Variable } = Object.create(null);
module: Module;
private reexportedExternalNamespaces: ExternalVariable[] = [];
private referencedEarly = false;
private references: Identifier[] = [];
private syntheticNamedExports: boolean;
constructor(context: AstContext, syntheticNamedExports: boolean) {
super(context.getModuleName());
this.context = context;
this.module = context.module;
this.syntheticNamedExports = syntheticNamedExports;
}
addReference(identifier: Identifier) {
this.references.push(identifier);
this.name = identifier.name;
}
// This is only called if "UNKNOWN_PATH" is reassigned as in all other situations, either the
// build fails due to an illegal namespace reassignment or MemberExpression already forwards
// the reassignment to the right variable. This means we lost track of this variable and thus
// need to reassign all exports.
deoptimizePath() {
for (const key in this.memberVariables) {
this.memberVariables[key].deoptimizePath(UNKNOWN_PATH);
}
}
include(context: InclusionContext) {
if (!this.included) {
this.included = true;
for (const identifier of this.references) {
if (identifier.context.getModuleExecIndex() <= this.context.getModuleExecIndex()) {
this.referencedEarly = true;
break;
}
}
this.reexportedExternalNamespaces = this.context.includeAndGetReexportedExternalNamespaces();
if (this.context.preserveModules) {
for (const memberName of Object.keys(this.memberVariables))
this.memberVariables[memberName].include(context);
} else {
for (const memberName of Object.keys(this.memberVariables))
this.context.includeVariable(context, this.memberVariables[memberName]);
}
}
}
initialise() {
for (const name of this.context.getExports().concat(this.context.getReexports())) {
if (name[0] !== '*') {
this.memberVariables[name] = this.context.traceExport(name);
}
}
}
renderBlock(options: RenderOptions) {
const _ = options.compact ? '' : ' ';
const n = options.compact ? '' : '\n';
const t = options.indent;
const members = Object.keys(this.memberVariables).map(name => {
const original = this.memberVariables[name];
if (this.referencedEarly || original.isReassigned) {
return `${t}get ${name}${_}()${_}{${_}return ${original.getName()}${
options.compact ? '' : ';'
}${_}}`;
}
const safeName = RESERVED_NAMES[name] ? `'${name}'` : name;
return `${t}${safeName}: ${original.getName()}`;
});
if (options.namespaceToStringTag) {
members.unshift(`${t}[Symbol.toStringTag]:${_}'Module'`);
}
const hasExternalReexports = this.reexportedExternalNamespaces.length > 0;
if (!hasExternalReexports) members.unshift(`${t}__proto__:${_}null`);
let output = `{${n}${members.join(`,${n}`)}${n}}`;
if (hasExternalReexports || this.syntheticNamedExports) {
const assignmentArgs = members.length > 0 ? [output] : [];
if (hasExternalReexports) {
assignmentArgs.unshift(
'/*#__PURE__*/Object.create(null)',
...this.reexportedExternalNamespaces.map(variable => variable.getName())
);
}
if (this.syntheticNamedExports) {
assignmentArgs.push(this.module.getDefaultExport().getName());
}
output = `/*#__PURE__*/Object.assign(${assignmentArgs.join(`,${_}`)})`;
}
if (options.freeze) {
output = `/*#__PURE__*/Object.freeze(${output})`;
}
const name = this.getName();
output = `${options.varOrConst} ${name}${_}=${_}${output};`;
if (options.format === 'system' && this.exportName) {
output += `${n}exports('${this.exportName}',${_}${name});`;
}
return output;
}
renderFirst() {
return this.referencedEarly;
}
}
NamespaceVariable.prototype.isNamespace = true;