webpack 4.1.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +719 -721
  2. package/bin/webpack.js +69 -10
  3. package/lib/APIPlugin.js +84 -84
  4. package/lib/AmdMainTemplatePlugin.js +75 -77
  5. package/lib/AsyncDependencyToInitialChunkError.js +21 -23
  6. package/lib/BannerPlugin.js +101 -101
  7. package/lib/Chunk.js +477 -469
  8. package/lib/ChunkTemplate.js +51 -53
  9. package/lib/Compilation.js +1858 -1851
  10. package/lib/Compiler.js +493 -478
  11. package/lib/ConcurrentCompilationError.js +19 -0
  12. package/lib/ContextModule.js +696 -685
  13. package/lib/ContextModuleFactory.js +245 -243
  14. package/lib/DefinePlugin.js +197 -197
  15. package/lib/DelegatedModule.js +101 -101
  16. package/lib/DependenciesBlockVariable.js +51 -52
  17. package/lib/Dependency.js +53 -52
  18. package/lib/DllModule.js +54 -54
  19. package/lib/DllModuleFactory.js +29 -29
  20. package/lib/EnvironmentPlugin.js +65 -67
  21. package/lib/EvalDevToolModuleTemplatePlugin.js +60 -60
  22. package/lib/EvalSourceMapDevToolModuleTemplatePlugin.js +105 -105
  23. package/lib/ExportPropertyMainTemplatePlugin.js +40 -40
  24. package/lib/ExternalModule.js +159 -159
  25. package/lib/FunctionModuleTemplatePlugin.js +98 -98
  26. package/lib/HotModuleReplacement.runtime.js +631 -631
  27. package/lib/HotModuleReplacementPlugin.js +407 -406
  28. package/lib/HotUpdateChunkTemplate.js +78 -80
  29. package/lib/JavascriptGenerator.js +228 -229
  30. package/lib/JavascriptModulesPlugin.js +184 -158
  31. package/lib/JsonGenerator.js +42 -42
  32. package/lib/MainTemplate.js +406 -402
  33. package/lib/Module.js +343 -340
  34. package/lib/ModuleBuildError.js +42 -42
  35. package/lib/ModuleError.js +28 -28
  36. package/lib/ModuleFilenameHelpers.js +166 -166
  37. package/lib/ModuleTemplate.js +77 -79
  38. package/lib/ModuleWarning.js +30 -30
  39. package/lib/MultiCompiler.js +271 -259
  40. package/lib/MultiModule.js +78 -75
  41. package/lib/MultiModuleFactory.js +23 -23
  42. package/lib/MultiWatching.js +38 -37
  43. package/lib/NoModeWarning.js +23 -21
  44. package/lib/NormalModule.js +478 -470
  45. package/lib/NormalModuleFactory.js +483 -481
  46. package/lib/OptionsDefaulter.js +80 -86
  47. package/lib/Parser.js +2074 -2071
  48. package/lib/ProgressPlugin.js +231 -231
  49. package/lib/RawModule.js +54 -55
  50. package/lib/RecordIdsPlugin.js +160 -160
  51. package/lib/RemovedPluginError.js +13 -13
  52. package/lib/ResolverFactory.js +64 -67
  53. package/lib/RuntimeTemplate.js +267 -297
  54. package/lib/SetVarMainTemplatePlugin.js +57 -57
  55. package/lib/SourceMapDevToolPlugin.js +302 -308
  56. package/lib/Stats.js +1234 -1212
  57. package/lib/Template.js +205 -205
  58. package/lib/TemplatedPathPlugin.js +170 -143
  59. package/lib/UmdMainTemplatePlugin.js +264 -269
  60. package/lib/Watching.js +193 -193
  61. package/lib/WebAssemblyParser.js +50 -54
  62. package/lib/WebpackOptionsApply.js +401 -401
  63. package/lib/WebpackOptionsDefaulter.js +337 -317
  64. package/lib/WebpackOptionsValidationError.js +316 -319
  65. package/lib/debug/ProfilingPlugin.js +409 -405
  66. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +328 -311
  67. package/lib/dependencies/AMDRequireContextDependency.js +20 -20
  68. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +270 -241
  69. package/lib/dependencies/HarmonyAcceptImportDependency.js +23 -23
  70. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +620 -606
  71. package/lib/dependencies/HarmonyExportSpecifierDependency.js +53 -53
  72. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +214 -214
  73. package/lib/dependencies/HarmonyImportSpecifierDependency.js +154 -156
  74. package/lib/dependencies/ImportDependenciesBlock.js +17 -17
  75. package/lib/dependencies/ImportDependency.js +34 -34
  76. package/lib/dependencies/ImportEagerDependency.js +32 -32
  77. package/lib/dependencies/ImportParserPlugin.js +175 -179
  78. package/lib/dependencies/ImportWeakDependency.js +34 -34
  79. package/lib/dependencies/JsonExportsDependency.js +25 -25
  80. package/lib/dependencies/ModuleDependency.js +20 -20
  81. package/lib/dependencies/NullDependency.js +20 -20
  82. package/lib/dependencies/RequireContextDependency.js +22 -22
  83. package/lib/dependencies/RequireIncludeDependency.js +40 -40
  84. package/lib/dependencies/WebpackMissingModule.js +20 -22
  85. package/lib/node/NodeChunkTemplatePlugin.js +31 -31
  86. package/lib/node/NodeHotUpdateChunkTemplatePlugin.js +36 -36
  87. package/lib/node/NodeMainTemplatePlugin.js +320 -273
  88. package/lib/node/ReadFileCompileWasmMainTemplatePlugin.js +113 -115
  89. package/lib/optimize/AggressiveSplittingPlugin.js +281 -281
  90. package/lib/optimize/ConcatenatedModule.js +1364 -1366
  91. package/lib/optimize/RemoveParentModulesPlugin.js +114 -114
  92. package/lib/optimize/SplitChunksPlugin.js +519 -491
  93. package/lib/performance/SizeLimitsPlugin.js +105 -105
  94. package/lib/util/TrackingSet.js +35 -35
  95. package/lib/util/objectToMap.js +10 -10
  96. package/lib/wasm/WasmModuleTemplatePlugin.js +106 -106
  97. package/lib/web/JsonpChunkTemplatePlugin.js +47 -47
  98. package/lib/web/JsonpExportMainTemplatePlugin.js +47 -47
  99. package/lib/web/JsonpHotUpdateChunkTemplatePlugin.js +39 -39
  100. package/lib/web/JsonpMainTemplatePlugin.js +425 -403
  101. package/lib/webpack.js +182 -179
  102. package/lib/webworker/WebWorkerChunkTemplatePlugin.js +35 -35
  103. package/lib/webworker/WebWorkerHotUpdateChunkTemplatePlugin.js +40 -40
  104. package/lib/webworker/WebWorkerMainTemplatePlugin.js +177 -154
  105. package/package.json +9 -8
  106. package/schemas/WebpackOptions.json +1973 -1951
  107. package/schemas/ajv.absolutePath.js +55 -29
  108. package/schemas/plugins/BannerPlugin.json +85 -85
  109. package/schemas/plugins/DllPlugin.json +28 -28
  110. package/schemas/plugins/DllReferencePlugin.json +99 -99
  111. package/schemas/plugins/HashedModuleIdsPlugin.json +24 -24
  112. package/schemas/plugins/LoaderOptionsPlugin.json +26 -26
  113. package/schemas/plugins/SourceMapDevToolPlugin.json +187 -187
  114. package/schemas/plugins/WatchIgnorePlugin.json +16 -16
  115. package/schemas/plugins/debug/ProfilingPlugin.json +12 -12
  116. package/schemas/plugins/optimize/AggressiveSplittingPlugin.json +22 -22
  117. package/schemas/plugins/optimize/LimitChunkCountPlugin.json +15 -15
  118. package/schemas/plugins/optimize/MinChunkSizePlugin.json +13 -13
package/lib/Parser.js CHANGED
@@ -1,2071 +1,2074 @@
1
- /*
2
- MIT License http://www.opensource.org/licenses/mit-license.php
3
- Author Tobias Koppers @sokra
4
- */
5
- "use strict";
6
-
7
- // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
8
-
9
- const acorn = require("acorn-dynamic-import").default;
10
- const Tapable = require("tapable").Tapable;
11
- const SyncBailHook = require("tapable").SyncBailHook;
12
- const HookMap = require("tapable/lib/HookMap");
13
- const vm = require("vm");
14
- const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
15
- const StackedSetMap = require("./util/StackedSetMap");
16
- const TrackingSet = require("./util/TrackingSet");
17
-
18
- const joinRanges = (startRange, endRange) => {
19
- if (!endRange) return startRange;
20
- if (!startRange) return endRange;
21
- return [startRange[0], endRange[1]];
22
- };
23
-
24
- const defaultParserOptions = {
25
- ranges: true,
26
- locations: true,
27
- ecmaVersion: 2018,
28
- sourceType: "module",
29
- onComment: null,
30
- plugins: {
31
- dynamicImport: true
32
- }
33
- };
34
-
35
- class Parser extends Tapable {
36
- constructor(options, sourceType = "auto") {
37
- super();
38
- this.hooks = {
39
- evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])),
40
- evaluate: new HookMap(() => new SyncBailHook(["expression"])),
41
- evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])),
42
- evaluateDefinedIdentifier: new HookMap(
43
- () => new SyncBailHook(["expression"])
44
- ),
45
- evaluateCallExpressionMember: new HookMap(
46
- () => new SyncBailHook(["expression", "param"])
47
- ),
48
- statement: new SyncBailHook(["statement"]),
49
- statementIf: new SyncBailHook(["statement"]),
50
- label: new HookMap(() => new SyncBailHook(["statement"])),
51
- import: new SyncBailHook(["statement", "source"]),
52
- importSpecifier: new SyncBailHook([
53
- "statement",
54
- "source",
55
- "exportName",
56
- "identifierName"
57
- ]),
58
- export: new SyncBailHook(["statement"]),
59
- exportImport: new SyncBailHook(["statement", "source"]),
60
- exportDeclaration: new SyncBailHook(["statement", "declaration"]),
61
- exportExpression: new SyncBailHook(["statement", "declaration"]),
62
- exportSpecifier: new SyncBailHook([
63
- "statement",
64
- "identifierName",
65
- "exportName",
66
- "index"
67
- ]),
68
- exportImportSpecifier: new SyncBailHook([
69
- "statement",
70
- "source",
71
- "identifierName",
72
- "exportName",
73
- "index"
74
- ]),
75
- varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])),
76
- varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])),
77
- varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])),
78
- varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])),
79
- canRename: new HookMap(() => new SyncBailHook(["initExpression"])),
80
- rename: new HookMap(() => new SyncBailHook(["initExpression"])),
81
- assigned: new HookMap(() => new SyncBailHook(["expression"])),
82
- assign: new HookMap(() => new SyncBailHook(["expression"])),
83
- typeof: new HookMap(() => new SyncBailHook(["expression"])),
84
- importCall: new SyncBailHook(["expression"]),
85
- call: new HookMap(() => new SyncBailHook(["expression"])),
86
- callAnyMember: new HookMap(() => new SyncBailHook(["expression"])),
87
- new: new HookMap(() => new SyncBailHook(["expression"])),
88
- expression: new HookMap(() => new SyncBailHook(["expression"])),
89
- expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])),
90
- expressionConditionalOperator: new SyncBailHook(["expression"]),
91
- program: new SyncBailHook(["ast", "comments"])
92
- };
93
- const HOOK_MAP_COMPAT_CONFIG = {
94
- evaluateTypeof: /^evaluate typeof (.+)$/,
95
- evaluateIdentifier: /^evaluate Identifier (.+)$/,
96
- evaluateDefinedIdentifier: /^evaluate defined Identifier (.+)$/,
97
- evaluateCallExpressionMember: /^evaluate CallExpression .(.+)$/,
98
- evaluate: /^evaluate (.+)$/,
99
- label: /^label (.+)$/,
100
- varDeclarationLet: /^var-let (.+)$/,
101
- varDeclarationConst: /^var-const (.+)$/,
102
- varDeclarationVar: /^var-var (.+)$/,
103
- varDeclaration: /^var (.+)$/,
104
- canRename: /^can-rename (.+)$/,
105
- rename: /^rename (.+)$/,
106
- typeof: /^typeof (.+)$/,
107
- assigned: /^assigned (.+)$/,
108
- assign: /^assign (.+)$/,
109
- callAnyMember: /^call (.+)\.\*$/,
110
- call: /^call (.+)$/,
111
- new: /^new (.+)$/,
112
- expressionConditionalOperator: /^expression \?:$/,
113
- expressionAnyMember: /^expression (.+)\.\*$/,
114
- expression: /^expression (.+)$/
115
- };
116
- this._pluginCompat.tap("Parser", options => {
117
- for (const name of Object.keys(HOOK_MAP_COMPAT_CONFIG)) {
118
- const regexp = HOOK_MAP_COMPAT_CONFIG[name];
119
- const match = regexp.exec(options.name);
120
- if (match) {
121
- if (match[1])
122
- this.hooks[name].tap(
123
- match[1],
124
- options.fn.name || "unnamed compat plugin",
125
- options.fn.bind(this)
126
- );
127
- else
128
- this.hooks[name].tap(
129
- options.fn.name || "unnamed compat plugin",
130
- options.fn.bind(this)
131
- );
132
- return true;
133
- }
134
- }
135
- });
136
- this.options = options;
137
- this.sourceType = sourceType;
138
- this.scope = undefined;
139
- this.state = undefined;
140
- this.comments = undefined;
141
- this.initializeEvaluating();
142
- }
143
-
144
- initializeEvaluating() {
145
- this.hooks.evaluate.for("Literal").tap("Parser", expr => {
146
- switch (typeof expr.value) {
147
- case "number":
148
- return new BasicEvaluatedExpression()
149
- .setNumber(expr.value)
150
- .setRange(expr.range);
151
- case "string":
152
- return new BasicEvaluatedExpression()
153
- .setString(expr.value)
154
- .setRange(expr.range);
155
- case "boolean":
156
- return new BasicEvaluatedExpression()
157
- .setBoolean(expr.value)
158
- .setRange(expr.range);
159
- }
160
- if (expr.value === null)
161
- return new BasicEvaluatedExpression().setNull().setRange(expr.range);
162
- if (expr.value instanceof RegExp)
163
- return new BasicEvaluatedExpression()
164
- .setRegExp(expr.value)
165
- .setRange(expr.range);
166
- });
167
- this.hooks.evaluate.for("LogicalExpression").tap("Parser", expr => {
168
- let left;
169
- let leftAsBool;
170
- let right;
171
- if (expr.operator === "&&") {
172
- left = this.evaluateExpression(expr.left);
173
- leftAsBool = left && left.asBool();
174
- if (leftAsBool === false) return left.setRange(expr.range);
175
- if (leftAsBool !== true) return;
176
- right = this.evaluateExpression(expr.right);
177
- return right.setRange(expr.range);
178
- } else if (expr.operator === "||") {
179
- left = this.evaluateExpression(expr.left);
180
- leftAsBool = left && left.asBool();
181
- if (leftAsBool === true) return left.setRange(expr.range);
182
- if (leftAsBool !== false) return;
183
- right = this.evaluateExpression(expr.right);
184
- return right.setRange(expr.range);
185
- }
186
- });
187
- this.hooks.evaluate.for("BinaryExpression").tap("Parser", expr => {
188
- let left;
189
- let right;
190
- let res;
191
- if (expr.operator === "+") {
192
- left = this.evaluateExpression(expr.left);
193
- right = this.evaluateExpression(expr.right);
194
- if (!left || !right) return;
195
- res = new BasicEvaluatedExpression();
196
- if (left.isString()) {
197
- if (right.isString()) {
198
- res.setString(left.string + right.string);
199
- } else if (right.isNumber()) {
200
- res.setString(left.string + right.number);
201
- } else if (
202
- right.isWrapped() &&
203
- right.prefix &&
204
- right.prefix.isString()
205
- ) {
206
- res.setWrapped(
207
- new BasicEvaluatedExpression()
208
- .setString(left.string + right.prefix.string)
209
- .setRange(joinRanges(left.range, right.prefix.range)),
210
- right.postfix
211
- );
212
- } else if (right.isWrapped()) {
213
- res.setWrapped(
214
- new BasicEvaluatedExpression()
215
- .setString(left.string)
216
- .setRange(left.range),
217
- right.postfix
218
- );
219
- } else {
220
- res.setWrapped(left, null);
221
- }
222
- } else if (left.isNumber()) {
223
- if (right.isString()) {
224
- res.setString(left.number + right.string);
225
- } else if (right.isNumber()) {
226
- res.setNumber(left.number + right.number);
227
- }
228
- } else if (left.isWrapped()) {
229
- if (left.postfix && left.postfix.isString() && right.isString()) {
230
- res.setWrapped(
231
- left.prefix,
232
- new BasicEvaluatedExpression()
233
- .setString(left.postfix.string + right.string)
234
- .setRange(joinRanges(left.postfix.range, right.range))
235
- );
236
- } else if (
237
- left.postfix &&
238
- left.postfix.isString() &&
239
- right.isNumber()
240
- ) {
241
- res.setWrapped(
242
- left.prefix,
243
- new BasicEvaluatedExpression()
244
- .setString(left.postfix.string + right.number)
245
- .setRange(joinRanges(left.postfix.range, right.range))
246
- );
247
- } else if (right.isString()) {
248
- res.setWrapped(left.prefix, right);
249
- } else if (right.isNumber()) {
250
- res.setWrapped(
251
- left.prefix,
252
- new BasicEvaluatedExpression()
253
- .setString(right.number + "")
254
- .setRange(right.range)
255
- );
256
- } else {
257
- res.setWrapped(left.prefix, new BasicEvaluatedExpression());
258
- }
259
- } else {
260
- if (right.isString()) {
261
- res.setWrapped(null, right);
262
- }
263
- }
264
- res.setRange(expr.range);
265
- return res;
266
- } else if (expr.operator === "-") {
267
- left = this.evaluateExpression(expr.left);
268
- right = this.evaluateExpression(expr.right);
269
- if (!left || !right) return;
270
- if (!left.isNumber() || !right.isNumber()) return;
271
- res = new BasicEvaluatedExpression();
272
- res.setNumber(left.number - right.number);
273
- res.setRange(expr.range);
274
- return res;
275
- } else if (expr.operator === "*") {
276
- left = this.evaluateExpression(expr.left);
277
- right = this.evaluateExpression(expr.right);
278
- if (!left || !right) return;
279
- if (!left.isNumber() || !right.isNumber()) return;
280
- res = new BasicEvaluatedExpression();
281
- res.setNumber(left.number * right.number);
282
- res.setRange(expr.range);
283
- return res;
284
- } else if (expr.operator === "/") {
285
- left = this.evaluateExpression(expr.left);
286
- right = this.evaluateExpression(expr.right);
287
- if (!left || !right) return;
288
- if (!left.isNumber() || !right.isNumber()) return;
289
- res = new BasicEvaluatedExpression();
290
- res.setNumber(left.number / right.number);
291
- res.setRange(expr.range);
292
- return res;
293
- } else if (expr.operator === "**") {
294
- left = this.evaluateExpression(expr.left);
295
- right = this.evaluateExpression(expr.right);
296
- if (!left || !right) return;
297
- if (!left.isNumber() || !right.isNumber()) return;
298
- res = new BasicEvaluatedExpression();
299
- res.setNumber(Math.pow(left.number, right.number));
300
- res.setRange(expr.range);
301
- return res;
302
- } else if (expr.operator === "==" || expr.operator === "===") {
303
- left = this.evaluateExpression(expr.left);
304
- right = this.evaluateExpression(expr.right);
305
- if (!left || !right) return;
306
- res = new BasicEvaluatedExpression();
307
- res.setRange(expr.range);
308
- if (left.isString() && right.isString()) {
309
- return res.setBoolean(left.string === right.string);
310
- } else if (left.isNumber() && right.isNumber()) {
311
- return res.setBoolean(left.number === right.number);
312
- } else if (left.isBoolean() && right.isBoolean()) {
313
- return res.setBoolean(left.bool === right.bool);
314
- }
315
- } else if (expr.operator === "!=" || expr.operator === "!==") {
316
- left = this.evaluateExpression(expr.left);
317
- right = this.evaluateExpression(expr.right);
318
- if (!left || !right) return;
319
- res = new BasicEvaluatedExpression();
320
- res.setRange(expr.range);
321
- if (left.isString() && right.isString()) {
322
- return res.setBoolean(left.string !== right.string);
323
- } else if (left.isNumber() && right.isNumber()) {
324
- return res.setBoolean(left.number !== right.number);
325
- } else if (left.isBoolean() && right.isBoolean()) {
326
- return res.setBoolean(left.bool !== right.bool);
327
- }
328
- } else if (expr.operator === "&") {
329
- left = this.evaluateExpression(expr.left);
330
- right = this.evaluateExpression(expr.right);
331
- if (!left || !right) return;
332
- if (!left.isNumber() || !right.isNumber()) return;
333
- res = new BasicEvaluatedExpression();
334
- res.setNumber(left.number & right.number);
335
- res.setRange(expr.range);
336
- return res;
337
- } else if (expr.operator === "|") {
338
- left = this.evaluateExpression(expr.left);
339
- right = this.evaluateExpression(expr.right);
340
- if (!left || !right) return;
341
- if (!left.isNumber() || !right.isNumber()) return;
342
- res = new BasicEvaluatedExpression();
343
- res.setNumber(left.number | right.number);
344
- res.setRange(expr.range);
345
- return res;
346
- } else if (expr.operator === "^") {
347
- left = this.evaluateExpression(expr.left);
348
- right = this.evaluateExpression(expr.right);
349
- if (!left || !right) return;
350
- if (!left.isNumber() || !right.isNumber()) return;
351
- res = new BasicEvaluatedExpression();
352
- res.setNumber(left.number ^ right.number);
353
- res.setRange(expr.range);
354
- return res;
355
- } else if (expr.operator === ">>>") {
356
- left = this.evaluateExpression(expr.left);
357
- right = this.evaluateExpression(expr.right);
358
- if (!left || !right) return;
359
- if (!left.isNumber() || !right.isNumber()) return;
360
- res = new BasicEvaluatedExpression();
361
- res.setNumber(left.number >>> right.number);
362
- res.setRange(expr.range);
363
- return res;
364
- } else if (expr.operator === ">>") {
365
- left = this.evaluateExpression(expr.left);
366
- right = this.evaluateExpression(expr.right);
367
- if (!left || !right) return;
368
- if (!left.isNumber() || !right.isNumber()) return;
369
- res = new BasicEvaluatedExpression();
370
- res.setNumber(left.number >> right.number);
371
- res.setRange(expr.range);
372
- return res;
373
- } else if (expr.operator === "<<") {
374
- left = this.evaluateExpression(expr.left);
375
- right = this.evaluateExpression(expr.right);
376
- if (!left || !right) return;
377
- if (!left.isNumber() || !right.isNumber()) return;
378
- res = new BasicEvaluatedExpression();
379
- res.setNumber(left.number << right.number);
380
- res.setRange(expr.range);
381
- return res;
382
- }
383
- });
384
- this.hooks.evaluate.for("UnaryExpression").tap("Parser", expr => {
385
- if (expr.operator === "typeof") {
386
- let res;
387
- let name;
388
- if (expr.argument.type === "Identifier") {
389
- name =
390
- this.scope.renames.get(expr.argument.name) || expr.argument.name;
391
- if (!this.scope.definitions.has(name)) {
392
- const hook = this.hooks.evaluateTypeof.get(name);
393
- if (hook !== undefined) {
394
- res = hook.call(expr);
395
- if (res !== undefined) return res;
396
- }
397
- }
398
- }
399
- if (expr.argument.type === "MemberExpression") {
400
- const exprName = this.getNameForExpression(expr.argument);
401
- if (exprName && exprName.free) {
402
- const hook = this.hooks.evaluateTypeof.get(exprName.name);
403
- if (hook !== undefined) {
404
- res = hook.call(expr);
405
- if (res !== undefined) return res;
406
- }
407
- }
408
- }
409
- if (expr.argument.type === "FunctionExpression") {
410
- return new BasicEvaluatedExpression()
411
- .setString("function")
412
- .setRange(expr.range);
413
- }
414
- const arg = this.evaluateExpression(expr.argument);
415
- if (arg.isString() || arg.isWrapped())
416
- return new BasicEvaluatedExpression()
417
- .setString("string")
418
- .setRange(expr.range);
419
- else if (arg.isNumber())
420
- return new BasicEvaluatedExpression()
421
- .setString("number")
422
- .setRange(expr.range);
423
- else if (arg.isBoolean())
424
- return new BasicEvaluatedExpression()
425
- .setString("boolean")
426
- .setRange(expr.range);
427
- else if (arg.isArray() || arg.isConstArray() || arg.isRegExp())
428
- return new BasicEvaluatedExpression()
429
- .setString("object")
430
- .setRange(expr.range);
431
- } else if (expr.operator === "!") {
432
- const argument = this.evaluateExpression(expr.argument);
433
- if (!argument) return;
434
- if (argument.isBoolean()) {
435
- return new BasicEvaluatedExpression()
436
- .setBoolean(!argument.bool)
437
- .setRange(expr.range);
438
- } else if (argument.isTruthy()) {
439
- return new BasicEvaluatedExpression()
440
- .setBoolean(false)
441
- .setRange(expr.range);
442
- } else if (argument.isFalsy()) {
443
- return new BasicEvaluatedExpression()
444
- .setBoolean(true)
445
- .setRange(expr.range);
446
- } else if (argument.isString()) {
447
- return new BasicEvaluatedExpression()
448
- .setBoolean(!argument.string)
449
- .setRange(expr.range);
450
- } else if (argument.isNumber()) {
451
- return new BasicEvaluatedExpression()
452
- .setBoolean(!argument.number)
453
- .setRange(expr.range);
454
- }
455
- } else if (expr.operator === "~") {
456
- const argument = this.evaluateExpression(expr.argument);
457
- if (!argument) return;
458
- if (!argument.isNumber()) return;
459
- const res = new BasicEvaluatedExpression();
460
- res.setNumber(~argument.number);
461
- res.setRange(expr.range);
462
- return res;
463
- }
464
- });
465
- this.hooks.evaluateTypeof.for("undefined").tap("Parser", expr => {
466
- return new BasicEvaluatedExpression()
467
- .setString("undefined")
468
- .setRange(expr.range);
469
- });
470
- this.hooks.evaluate.for("Identifier").tap("Parser", expr => {
471
- const name = this.scope.renames.get(expr.name) || expr.name;
472
- if (!this.scope.definitions.has(expr.name)) {
473
- const hook = this.hooks.evaluateIdentifier.get(name);
474
- if (hook !== undefined) {
475
- const result = hook.call(expr);
476
- if (result) return result;
477
- }
478
- return new BasicEvaluatedExpression()
479
- .setIdentifier(name)
480
- .setRange(expr.range);
481
- } else {
482
- const hook = this.hooks.evaluateDefinedIdentifier.get(name);
483
- if (hook !== undefined) {
484
- return hook.call(expr);
485
- }
486
- }
487
- });
488
- this.hooks.evaluate.for("ThisExpression").tap("Parser", expr => {
489
- const name = this.scope.renames.get("this");
490
- if (name) {
491
- const hook = this.hooks.evaluateIdentifier.get(name);
492
- if (hook !== undefined) {
493
- const result = hook.call(expr);
494
- if (result) return result;
495
- }
496
- return new BasicEvaluatedExpression()
497
- .setIdentifier(name)
498
- .setRange(expr.range);
499
- }
500
- });
501
- this.hooks.evaluate.for("MemberExpression").tap("Parser", expression => {
502
- let exprName = this.getNameForExpression(expression);
503
- if (exprName) {
504
- if (exprName.free) {
505
- const hook = this.hooks.evaluateIdentifier.get(exprName.name);
506
- if (hook !== undefined) {
507
- const result = hook.call(expression);
508
- if (result) return result;
509
- }
510
- return new BasicEvaluatedExpression()
511
- .setIdentifier(exprName.name)
512
- .setRange(expression.range);
513
- } else {
514
- const hook = this.hooks.evaluateDefinedIdentifier.get(exprName.name);
515
- if (hook !== undefined) {
516
- return hook.call(expression);
517
- }
518
- }
519
- }
520
- });
521
- this.hooks.evaluate.for("CallExpression").tap("Parser", expr => {
522
- if (expr.callee.type !== "MemberExpression") return;
523
- if (
524
- expr.callee.property.type !==
525
- (expr.callee.computed ? "Literal" : "Identifier")
526
- )
527
- return;
528
- const param = this.evaluateExpression(expr.callee.object);
529
- if (!param) return;
530
- const property = expr.callee.property.name || expr.callee.property.value;
531
- const hook = this.hooks.evaluateCallExpressionMember.get(property);
532
- if (hook !== undefined) {
533
- return hook.call(expr, param);
534
- }
535
- });
536
- this.hooks.evaluateCallExpressionMember
537
- .for("replace")
538
- .tap("Parser", (expr, param) => {
539
- if (!param.isString()) return;
540
- if (expr.arguments.length !== 2) return;
541
- let arg1 = this.evaluateExpression(expr.arguments[0]);
542
- let arg2 = this.evaluateExpression(expr.arguments[1]);
543
- if (!arg1.isString() && !arg1.isRegExp()) return;
544
- arg1 = arg1.regExp || arg1.string;
545
- if (!arg2.isString()) return;
546
- arg2 = arg2.string;
547
- return new BasicEvaluatedExpression()
548
- .setString(param.string.replace(arg1, arg2))
549
- .setRange(expr.range);
550
- });
551
- ["substr", "substring"].forEach(fn => {
552
- this.hooks.evaluateCallExpressionMember
553
- .for(fn)
554
- .tap("Parser", (expr, param) => {
555
- if (!param.isString()) return;
556
- let arg1;
557
- let result,
558
- str = param.string;
559
- switch (expr.arguments.length) {
560
- case 1:
561
- arg1 = this.evaluateExpression(expr.arguments[0]);
562
- if (!arg1.isNumber()) return;
563
- result = str[fn](arg1.number);
564
- break;
565
- case 2: {
566
- arg1 = this.evaluateExpression(expr.arguments[0]);
567
- const arg2 = this.evaluateExpression(expr.arguments[1]);
568
- if (!arg1.isNumber()) return;
569
- if (!arg2.isNumber()) return;
570
- result = str[fn](arg1.number, arg2.number);
571
- break;
572
- }
573
- default:
574
- return;
575
- }
576
- return new BasicEvaluatedExpression()
577
- .setString(result)
578
- .setRange(expr.range);
579
- });
580
- });
581
-
582
- /**
583
- * @param {string} kind "cooked" | "raw"
584
- * @param {any[]} quasis quasis
585
- * @param {any[]} expressions expressions
586
- * @return {BasicEvaluatedExpression[]} Simplified template
587
- */
588
- const getSimplifiedTemplateResult = (kind, quasis, expressions) => {
589
- const parts = [];
590
-
591
- for (let i = 0; i < quasis.length; i++) {
592
- parts.push(
593
- new BasicEvaluatedExpression()
594
- .setString(quasis[i].value[kind])
595
- .setRange(quasis[i].range)
596
- );
597
-
598
- if (i > 0) {
599
- const prevExpr = parts[parts.length - 2],
600
- lastExpr = parts[parts.length - 1];
601
- const expr = this.evaluateExpression(expressions[i - 1]);
602
- if (!(expr.isString() || expr.isNumber())) continue;
603
-
604
- prevExpr.setString(
605
- prevExpr.string +
606
- (expr.isString() ? expr.string : expr.number) +
607
- lastExpr.string
608
- );
609
- prevExpr.setRange([prevExpr.range[0], lastExpr.range[1]]);
610
- parts.pop();
611
- }
612
- }
613
- return parts;
614
- };
615
-
616
- this.hooks.evaluate.for("TemplateLiteral").tap("Parser", node => {
617
- const parts = getSimplifiedTemplateResult.call(
618
- this,
619
- "cooked",
620
- node.quasis,
621
- node.expressions
622
- );
623
- if (parts.length === 1) {
624
- return parts[0].setRange(node.range);
625
- }
626
- return new BasicEvaluatedExpression()
627
- .setTemplateString(parts)
628
- .setRange(node.range);
629
- });
630
- this.hooks.evaluate.for("TaggedTemplateExpression").tap("Parser", node => {
631
- if (this.evaluateExpression(node.tag).identifier !== "String.raw") return;
632
- const parts = getSimplifiedTemplateResult.call(
633
- this,
634
- "raw",
635
- node.quasi.quasis,
636
- node.quasi.expressions
637
- );
638
- return new BasicEvaluatedExpression()
639
- .setTemplateString(parts)
640
- .setRange(node.range);
641
- });
642
-
643
- this.hooks.evaluateCallExpressionMember
644
- .for("concat")
645
- .tap("Parser", (expr, param) => {
646
- if (!param.isString() && !param.isWrapped()) return;
647
-
648
- let stringSuffix = null;
649
- let hasUnknownParams = false;
650
- for (let i = expr.arguments.length - 1; i >= 0; i--) {
651
- const argExpr = this.evaluateExpression(expr.arguments[i]);
652
- if (!argExpr.isString() && !argExpr.isNumber()) {
653
- hasUnknownParams = true;
654
- break;
655
- }
656
-
657
- const value = argExpr.isString()
658
- ? argExpr.string
659
- : "" + argExpr.number;
660
-
661
- const newString = value + (stringSuffix ? stringSuffix.string : "");
662
- const newRange = [
663
- argExpr.range[0],
664
- (stringSuffix || argExpr).range[1]
665
- ];
666
- stringSuffix = new BasicEvaluatedExpression()
667
- .setString(newString)
668
- .setRange(newRange);
669
- }
670
-
671
- if (hasUnknownParams) {
672
- const prefix = param.isString() ? param : param.prefix;
673
- return new BasicEvaluatedExpression()
674
- .setWrapped(prefix, stringSuffix)
675
- .setRange(expr.range);
676
- } else if (param.isWrapped()) {
677
- const postfix = stringSuffix || param.postfix;
678
- return new BasicEvaluatedExpression()
679
- .setWrapped(param.prefix, postfix)
680
- .setRange(expr.range);
681
- } else {
682
- const newString =
683
- param.string + (stringSuffix ? stringSuffix.string : "");
684
- return new BasicEvaluatedExpression()
685
- .setString(newString)
686
- .setRange(expr.range);
687
- }
688
- });
689
- this.hooks.evaluateCallExpressionMember
690
- .for("split")
691
- .tap("Parser", (expr, param) => {
692
- if (!param.isString()) return;
693
- if (expr.arguments.length !== 1) return;
694
- let result;
695
- const arg = this.evaluateExpression(expr.arguments[0]);
696
- if (arg.isString()) {
697
- result = param.string.split(arg.string);
698
- } else if (arg.isRegExp()) {
699
- result = param.string.split(arg.regExp);
700
- } else return;
701
- return new BasicEvaluatedExpression()
702
- .setArray(result)
703
- .setRange(expr.range);
704
- });
705
- this.hooks.evaluate.for("ConditionalExpression").tap("Parser", expr => {
706
- const condition = this.evaluateExpression(expr.test);
707
- const conditionValue = condition.asBool();
708
- let res;
709
- if (conditionValue === undefined) {
710
- const consequent = this.evaluateExpression(expr.consequent);
711
- const alternate = this.evaluateExpression(expr.alternate);
712
- if (!consequent || !alternate) return;
713
- res = new BasicEvaluatedExpression();
714
- if (consequent.isConditional()) res.setOptions(consequent.options);
715
- else res.setOptions([consequent]);
716
- if (alternate.isConditional()) res.addOptions(alternate.options);
717
- else res.addOptions([alternate]);
718
- } else {
719
- res = this.evaluateExpression(
720
- conditionValue ? expr.consequent : expr.alternate
721
- );
722
- }
723
- res.setRange(expr.range);
724
- return res;
725
- });
726
- this.hooks.evaluate.for("ArrayExpression").tap("Parser", expr => {
727
- const items = expr.elements.map(element => {
728
- return element !== null && this.evaluateExpression(element);
729
- });
730
- if (!items.every(Boolean)) return;
731
- return new BasicEvaluatedExpression()
732
- .setItems(items)
733
- .setRange(expr.range);
734
- });
735
- }
736
-
737
- getRenameIdentifier(expr) {
738
- const result = this.evaluateExpression(expr);
739
- if (!result) return;
740
- if (result.isIdentifier()) return result.identifier;
741
- return;
742
- }
743
-
744
- walkClass(classy) {
745
- if (classy.superClass) this.walkExpression(classy.superClass);
746
- if (classy.body && classy.body.type === "ClassBody") {
747
- const wasTopLevel = this.scope.topLevelScope;
748
- this.scope.topLevelScope = false;
749
- for (const methodDefinition of classy.body.body) {
750
- if (methodDefinition.type === "MethodDefinition")
751
- this.walkMethodDefinition(methodDefinition);
752
- }
753
- this.scope.topLevelScope = wasTopLevel;
754
- }
755
- }
756
-
757
- walkMethodDefinition(methodDefinition) {
758
- if (methodDefinition.computed && methodDefinition.key)
759
- this.walkExpression(methodDefinition.key);
760
- if (methodDefinition.value) this.walkExpression(methodDefinition.value);
761
- }
762
-
763
- // Prewalking iterates the scope for variable declarations
764
- prewalkStatements(statements) {
765
- for (let index = 0, len = statements.length; index < len; index++) {
766
- const statement = statements[index];
767
- this.prewalkStatement(statement);
768
- }
769
- }
770
-
771
- // Walking iterates the statements and expressions and processes them
772
- walkStatements(statements) {
773
- for (let index = 0, len = statements.length; index < len; index++) {
774
- const statement = statements[index];
775
- this.walkStatement(statement);
776
- }
777
- }
778
-
779
- prewalkStatement(statement) {
780
- switch (statement.type) {
781
- case "BlockStatement":
782
- this.prewalkBlockStatement(statement);
783
- break;
784
- case "ClassDeclaration":
785
- this.prewalkClassDeclaration(statement);
786
- break;
787
- case "DoWhileStatement":
788
- this.prewalkDoWhileStatement(statement);
789
- break;
790
- case "ExportAllDeclaration":
791
- this.prewalkExportAllDeclaration(statement);
792
- break;
793
- case "ExportDefaultDeclaration":
794
- this.prewalkExportDefaultDeclaration(statement);
795
- break;
796
- case "ExportNamedDeclaration":
797
- this.prewalkExportNamedDeclaration(statement);
798
- break;
799
- case "ForInStatement":
800
- this.prewalkForInStatement(statement);
801
- break;
802
- case "ForOfStatement":
803
- this.prewalkForOfStatement(statement);
804
- break;
805
- case "ForStatement":
806
- this.prewalkForStatement(statement);
807
- break;
808
- case "FunctionDeclaration":
809
- this.prewalkFunctionDeclaration(statement);
810
- break;
811
- case "IfStatement":
812
- this.prewalkIfStatement(statement);
813
- break;
814
- case "ImportDeclaration":
815
- this.prewalkImportDeclaration(statement);
816
- break;
817
- case "LabeledStatement":
818
- this.prewalkLabeledStatement(statement);
819
- break;
820
- case "SwitchStatement":
821
- this.prewalkSwitchStatement(statement);
822
- break;
823
- case "TryStatement":
824
- this.prewalkTryStatement(statement);
825
- break;
826
- case "VariableDeclaration":
827
- this.prewalkVariableDeclaration(statement);
828
- break;
829
- case "WhileStatement":
830
- this.prewalkWhileStatement(statement);
831
- break;
832
- case "WithStatement":
833
- this.prewalkWithStatement(statement);
834
- break;
835
- }
836
- }
837
-
838
- walkStatement(statement) {
839
- if (this.hooks.statement.call(statement) !== undefined) return;
840
- switch (statement.type) {
841
- case "BlockStatement":
842
- this.walkBlockStatement(statement);
843
- break;
844
- case "ClassDeclaration":
845
- this.walkClassDeclaration(statement);
846
- break;
847
- case "DoWhileStatement":
848
- this.walkDoWhileStatement(statement);
849
- break;
850
- case "ExportDefaultDeclaration":
851
- this.walkExportDefaultDeclaration(statement);
852
- break;
853
- case "ExportNamedDeclaration":
854
- this.walkExportNamedDeclaration(statement);
855
- break;
856
- case "ExpressionStatement":
857
- this.walkExpressionStatement(statement);
858
- break;
859
- case "ForInStatement":
860
- this.walkForInStatement(statement);
861
- break;
862
- case "ForOfStatement":
863
- this.walkForOfStatement(statement);
864
- break;
865
- case "ForStatement":
866
- this.walkForStatement(statement);
867
- break;
868
- case "FunctionDeclaration":
869
- this.walkFunctionDeclaration(statement);
870
- break;
871
- case "IfStatement":
872
- this.walkIfStatement(statement);
873
- break;
874
- case "LabeledStatement":
875
- this.walkLabeledStatement(statement);
876
- break;
877
- case "ReturnStatement":
878
- this.walkReturnStatement(statement);
879
- break;
880
- case "SwitchStatement":
881
- this.walkSwitchStatement(statement);
882
- break;
883
- case "ThrowStatement":
884
- this.walkThrowStatement(statement);
885
- break;
886
- case "TryStatement":
887
- this.walkTryStatement(statement);
888
- break;
889
- case "VariableDeclaration":
890
- this.walkVariableDeclaration(statement);
891
- break;
892
- case "WhileStatement":
893
- this.walkWhileStatement(statement);
894
- break;
895
- case "WithStatement":
896
- this.walkWithStatement(statement);
897
- break;
898
- }
899
- }
900
-
901
- // Real Statements
902
- prewalkBlockStatement(statement) {
903
- this.prewalkStatements(statement.body);
904
- }
905
-
906
- walkBlockStatement(statement) {
907
- this.walkStatements(statement.body);
908
- }
909
-
910
- walkExpressionStatement(statement) {
911
- this.walkExpression(statement.expression);
912
- }
913
-
914
- prewalkIfStatement(statement) {
915
- this.prewalkStatement(statement.consequent);
916
- if (statement.alternate) this.prewalkStatement(statement.alternate);
917
- }
918
-
919
- walkIfStatement(statement) {
920
- const result = this.hooks.statementIf.call(statement);
921
- if (result === undefined) {
922
- this.walkExpression(statement.test);
923
- this.walkStatement(statement.consequent);
924
- if (statement.alternate) this.walkStatement(statement.alternate);
925
- } else {
926
- if (result) this.walkStatement(statement.consequent);
927
- else if (statement.alternate) this.walkStatement(statement.alternate);
928
- }
929
- }
930
-
931
- prewalkLabeledStatement(statement) {
932
- this.prewalkStatement(statement.body);
933
- }
934
-
935
- walkLabeledStatement(statement) {
936
- const hook = this.hooks.label.get(statement.label.name);
937
- if (hook !== undefined) {
938
- const result = hook.call(statement);
939
- if (result === true) return;
940
- }
941
- this.walkStatement(statement.body);
942
- }
943
-
944
- prewalkWithStatement(statement) {
945
- this.prewalkStatement(statement.body);
946
- }
947
-
948
- walkWithStatement(statement) {
949
- this.walkExpression(statement.object);
950
- this.walkStatement(statement.body);
951
- }
952
-
953
- prewalkSwitchStatement(statement) {
954
- this.prewalkSwitchCases(statement.cases);
955
- }
956
-
957
- walkSwitchStatement(statement) {
958
- this.walkExpression(statement.discriminant);
959
- this.walkSwitchCases(statement.cases);
960
- }
961
-
962
- walkTerminatingStatement(statement) {
963
- if (statement.argument) this.walkExpression(statement.argument);
964
- }
965
-
966
- walkReturnStatement(statement) {
967
- this.walkTerminatingStatement(statement);
968
- }
969
-
970
- walkThrowStatement(statement) {
971
- this.walkTerminatingStatement(statement);
972
- }
973
-
974
- prewalkTryStatement(statement) {
975
- this.prewalkStatement(statement.block);
976
- }
977
-
978
- walkTryStatement(statement) {
979
- if (this.scope.inTry) {
980
- this.walkStatement(statement.block);
981
- } else {
982
- this.scope.inTry = true;
983
- this.walkStatement(statement.block);
984
- this.scope.inTry = false;
985
- }
986
- if (statement.handler) this.walkCatchClause(statement.handler);
987
- if (statement.finalizer) this.walkStatement(statement.finalizer);
988
- }
989
-
990
- prewalkWhileStatement(statement) {
991
- this.prewalkStatement(statement.body);
992
- }
993
-
994
- walkWhileStatement(statement) {
995
- this.walkExpression(statement.test);
996
- this.walkStatement(statement.body);
997
- }
998
-
999
- prewalkDoWhileStatement(statement) {
1000
- this.prewalkStatement(statement.body);
1001
- }
1002
-
1003
- walkDoWhileStatement(statement) {
1004
- this.walkStatement(statement.body);
1005
- this.walkExpression(statement.test);
1006
- }
1007
-
1008
- prewalkForStatement(statement) {
1009
- if (statement.init) {
1010
- if (statement.init.type === "VariableDeclaration")
1011
- this.prewalkStatement(statement.init);
1012
- }
1013
- this.prewalkStatement(statement.body);
1014
- }
1015
-
1016
- walkForStatement(statement) {
1017
- if (statement.init) {
1018
- if (statement.init.type === "VariableDeclaration")
1019
- this.walkStatement(statement.init);
1020
- else this.walkExpression(statement.init);
1021
- }
1022
- if (statement.test) this.walkExpression(statement.test);
1023
- if (statement.update) this.walkExpression(statement.update);
1024
- this.walkStatement(statement.body);
1025
- }
1026
-
1027
- prewalkForInStatement(statement) {
1028
- if (statement.left.type === "VariableDeclaration")
1029
- this.prewalkVariableDeclaration(statement.left);
1030
- this.prewalkStatement(statement.body);
1031
- }
1032
-
1033
- walkForInStatement(statement) {
1034
- if (statement.left.type === "VariableDeclaration")
1035
- this.walkVariableDeclaration(statement.left);
1036
- else this.walkPattern(statement.left);
1037
- this.walkExpression(statement.right);
1038
- this.walkStatement(statement.body);
1039
- }
1040
-
1041
- prewalkForOfStatement(statement) {
1042
- if (statement.left.type === "VariableDeclaration")
1043
- this.prewalkVariableDeclaration(statement.left);
1044
- this.prewalkStatement(statement.body);
1045
- }
1046
-
1047
- walkForOfStatement(statement) {
1048
- if (statement.left.type === "VariableDeclaration")
1049
- this.walkVariableDeclaration(statement.left);
1050
- else this.walkPattern(statement.left);
1051
- this.walkExpression(statement.right);
1052
- this.walkStatement(statement.body);
1053
- }
1054
-
1055
- // Declarations
1056
- prewalkFunctionDeclaration(statement) {
1057
- if (statement.id) {
1058
- this.scope.renames.set(statement.id.name, null);
1059
- this.scope.definitions.add(statement.id.name);
1060
- }
1061
- }
1062
-
1063
- walkFunctionDeclaration(statement) {
1064
- for (const param of statement.params) this.walkPattern(param);
1065
- this.inScope(statement.params, () => {
1066
- this.scope.topLevelScope = false;
1067
- if (statement.body.type === "BlockStatement") {
1068
- this.detectStrictMode(statement.body.body);
1069
- this.prewalkStatement(statement.body);
1070
- this.walkStatement(statement.body);
1071
- } else {
1072
- this.walkExpression(statement.body);
1073
- }
1074
- });
1075
- }
1076
-
1077
- prewalkImportDeclaration(statement) {
1078
- const source = statement.source.value;
1079
- this.hooks.import.call(statement, source);
1080
- for (const specifier of statement.specifiers) {
1081
- const name = specifier.local.name;
1082
- this.scope.renames.set(name, null);
1083
- this.scope.definitions.add(name);
1084
- switch (specifier.type) {
1085
- case "ImportDefaultSpecifier":
1086
- this.hooks.importSpecifier.call(statement, source, "default", name);
1087
- break;
1088
- case "ImportSpecifier":
1089
- this.hooks.importSpecifier.call(
1090
- statement,
1091
- source,
1092
- specifier.imported.name,
1093
- name
1094
- );
1095
- break;
1096
- case "ImportNamespaceSpecifier":
1097
- this.hooks.importSpecifier.call(statement, source, null, name);
1098
- break;
1099
- }
1100
- }
1101
- }
1102
-
1103
- prewalkExportNamedDeclaration(statement) {
1104
- let source;
1105
- if (statement.source) {
1106
- source = statement.source.value;
1107
- this.hooks.exportImport.call(statement, source);
1108
- } else {
1109
- this.hooks.export.call(statement);
1110
- }
1111
- if (statement.declaration) {
1112
- if (
1113
- !this.hooks.exportDeclaration.call(statement, statement.declaration)
1114
- ) {
1115
- const originalDefinitions = this.scope.definitions;
1116
- const tracker = new TrackingSet(this.scope.definitions);
1117
- this.scope.definitions = tracker;
1118
- this.prewalkStatement(statement.declaration);
1119
- const newDefs = Array.from(tracker.getAddedItems());
1120
- this.scope.definitions = originalDefinitions;
1121
- for (let index = newDefs.length - 1; index >= 0; index--) {
1122
- const def = newDefs[index];
1123
- this.hooks.exportSpecifier.call(statement, def, def, index);
1124
- }
1125
- }
1126
- }
1127
- if (statement.specifiers) {
1128
- for (
1129
- let specifierIndex = 0;
1130
- specifierIndex < statement.specifiers.length;
1131
- specifierIndex++
1132
- ) {
1133
- const specifier = statement.specifiers[specifierIndex];
1134
- switch (specifier.type) {
1135
- case "ExportSpecifier": {
1136
- const name = specifier.exported.name;
1137
- if (source)
1138
- this.hooks.exportImportSpecifier.call(
1139
- statement,
1140
- source,
1141
- specifier.local.name,
1142
- name,
1143
- specifierIndex
1144
- );
1145
- else
1146
- this.hooks.exportSpecifier.call(
1147
- statement,
1148
- specifier.local.name,
1149
- name,
1150
- specifierIndex
1151
- );
1152
- break;
1153
- }
1154
- }
1155
- }
1156
- }
1157
- }
1158
-
1159
- walkExportNamedDeclaration(statement) {
1160
- if (statement.declaration) {
1161
- this.walkStatement(statement.declaration);
1162
- }
1163
- }
1164
-
1165
- prewalkExportDefaultDeclaration(statement) {
1166
- if (statement.declaration.id) {
1167
- const originalDefinitions = this.scope.definitions;
1168
- const tracker = new TrackingSet(this.scope.definitions);
1169
- this.scope.definitions = tracker;
1170
- this.prewalkStatement(statement.declaration);
1171
- const newDefs = Array.from(tracker.getAddedItems());
1172
- this.scope.definitions = originalDefinitions;
1173
- for (let index = 0, len = newDefs.length; index < len; index++) {
1174
- const def = newDefs[index];
1175
- this.hooks.exportSpecifier.call(statement, def, "default");
1176
- }
1177
- }
1178
- }
1179
-
1180
- walkExportDefaultDeclaration(statement) {
1181
- this.hooks.export.call(statement);
1182
- if (statement.declaration.id) {
1183
- if (
1184
- !this.hooks.exportDeclaration.call(statement, statement.declaration)
1185
- ) {
1186
- this.walkStatement(statement.declaration);
1187
- }
1188
- } else {
1189
- // Acorn parses `export default function() {}` as `FunctionDeclaration` and
1190
- // `export default class {}` as `ClassDeclaration`, both with `id = null`.
1191
- // These nodes must be treated as expressions.
1192
- if (statement.declaration.type === "FunctionDeclaration") {
1193
- this.walkFunctionDeclaration(statement.declaration);
1194
- } else if (statement.declaration.type === "ClassDeclaration") {
1195
- this.walkClassDeclaration(statement.declaration);
1196
- } else {
1197
- this.walkExpression(statement.declaration);
1198
- }
1199
- if (!this.hooks.exportExpression.call(statement, statement.declaration)) {
1200
- this.hooks.exportSpecifier.call(
1201
- statement,
1202
- statement.declaration,
1203
- "default"
1204
- );
1205
- }
1206
- }
1207
- }
1208
-
1209
- prewalkExportAllDeclaration(statement) {
1210
- const source = statement.source.value;
1211
- this.hooks.exportImport.call(statement, source);
1212
- this.hooks.exportImportSpecifier.call(statement, source, null, null, 0);
1213
- }
1214
-
1215
- prewalkVariableDeclaration(statement) {
1216
- const hookMap =
1217
- statement.kind === "const"
1218
- ? this.hooks.varDeclarationConst
1219
- : statement.kind === "let"
1220
- ? this.hooks.varDeclarationLet
1221
- : this.hooks.varDeclarationVar;
1222
- for (const declarator of statement.declarations) {
1223
- switch (declarator.type) {
1224
- case "VariableDeclarator": {
1225
- this.enterPattern(declarator.id, (name, decl) => {
1226
- let hook = hookMap.get(name);
1227
- if (hook === undefined || !hook.call(decl)) {
1228
- hook = this.hooks.varDeclaration.get(name);
1229
- if (hook === undefined || !hook.call(decl)) {
1230
- this.scope.renames.set(name, null);
1231
- this.scope.definitions.add(name);
1232
- }
1233
- }
1234
- });
1235
- break;
1236
- }
1237
- }
1238
- }
1239
- }
1240
-
1241
- walkVariableDeclaration(statement) {
1242
- for (const declarator of statement.declarations) {
1243
- switch (declarator.type) {
1244
- case "VariableDeclarator": {
1245
- const renameIdentifier =
1246
- declarator.init && this.getRenameIdentifier(declarator.init);
1247
- if (renameIdentifier && declarator.id.type === "Identifier") {
1248
- const hook = this.hooks.canRename.get(renameIdentifier);
1249
- if (hook !== undefined && hook.call(declarator.init)) {
1250
- // renaming with "var a = b;"
1251
- const hook = this.hooks.rename.get(renameIdentifier);
1252
- if (hook === undefined || !hook.call(declarator.init)) {
1253
- this.scope.renames.set(
1254
- declarator.id.name,
1255
- this.scope.renames.get(renameIdentifier) || renameIdentifier
1256
- );
1257
- this.scope.definitions.delete(declarator.id.name);
1258
- }
1259
- break;
1260
- }
1261
- }
1262
- this.walkPattern(declarator.id);
1263
- if (declarator.init) this.walkExpression(declarator.init);
1264
- break;
1265
- }
1266
- }
1267
- }
1268
- }
1269
-
1270
- prewalkClassDeclaration(statement) {
1271
- if (statement.id) {
1272
- this.scope.renames.set(statement.id.name, null);
1273
- this.scope.definitions.add(statement.id.name);
1274
- }
1275
- }
1276
-
1277
- walkClassDeclaration(statement) {
1278
- this.walkClass(statement);
1279
- }
1280
-
1281
- prewalkSwitchCases(switchCases) {
1282
- for (let index = 0, len = switchCases.length; index < len; index++) {
1283
- const switchCase = switchCases[index];
1284
- this.prewalkStatements(switchCase.consequent);
1285
- }
1286
- }
1287
-
1288
- walkSwitchCases(switchCases) {
1289
- for (let index = 0, len = switchCases.length; index < len; index++) {
1290
- const switchCase = switchCases[index];
1291
-
1292
- if (switchCase.test) {
1293
- this.walkExpression(switchCase.test);
1294
- }
1295
- this.walkStatements(switchCase.consequent);
1296
- }
1297
- }
1298
-
1299
- walkCatchClause(catchClause) {
1300
- this.inScope([catchClause.param], () => {
1301
- this.prewalkStatement(catchClause.body);
1302
- this.walkStatement(catchClause.body);
1303
- });
1304
- }
1305
-
1306
- walkPattern(pattern) {
1307
- switch (pattern.type) {
1308
- case "ArrayPattern":
1309
- this.walkArrayPattern(pattern);
1310
- break;
1311
- case "AssignmentPattern":
1312
- this.walkAssignmentPattern(pattern);
1313
- break;
1314
- case "MemberExpression":
1315
- this.walkMemberExpression(pattern);
1316
- break;
1317
- case "ObjectPattern":
1318
- this.walkObjectPattern(pattern);
1319
- break;
1320
- case "RestElement":
1321
- this.walkRestElement(pattern);
1322
- break;
1323
- }
1324
- }
1325
-
1326
- walkAssignmentPattern(pattern) {
1327
- this.walkExpression(pattern.right);
1328
- this.walkPattern(pattern.left);
1329
- }
1330
-
1331
- walkObjectPattern(pattern) {
1332
- for (let i = 0, len = pattern.properties.length; i < len; i++) {
1333
- const prop = pattern.properties[i];
1334
- if (prop) {
1335
- if (prop.computed) this.walkExpression(prop.key);
1336
- if (prop.value) this.walkPattern(prop.value);
1337
- }
1338
- }
1339
- }
1340
-
1341
- walkArrayPattern(pattern) {
1342
- for (let i = 0, len = pattern.elements.length; i < len; i++) {
1343
- const element = pattern.elements[i];
1344
- if (element) this.walkPattern(element);
1345
- }
1346
- }
1347
-
1348
- walkRestElement(pattern) {
1349
- this.walkPattern(pattern.argument);
1350
- }
1351
-
1352
- walkExpressions(expressions) {
1353
- for (
1354
- let expressionsIndex = 0, len = expressions.length;
1355
- expressionsIndex < len;
1356
- expressionsIndex++
1357
- ) {
1358
- const expression = expressions[expressionsIndex];
1359
- if (expression) this.walkExpression(expression);
1360
- }
1361
- }
1362
-
1363
- walkExpression(expression) {
1364
- switch (expression.type) {
1365
- case "ArrayExpression":
1366
- this.walkArrayExpression(expression);
1367
- break;
1368
- case "ArrowFunctionExpression":
1369
- this.walkArrowFunctionExpression(expression);
1370
- break;
1371
- case "AssignmentExpression":
1372
- this.walkAssignmentExpression(expression);
1373
- break;
1374
- case "AwaitExpression":
1375
- this.walkAwaitExpression(expression);
1376
- break;
1377
- case "BinaryExpression":
1378
- this.walkBinaryExpression(expression);
1379
- break;
1380
- case "CallExpression":
1381
- this.walkCallExpression(expression);
1382
- break;
1383
- case "ClassExpression":
1384
- this.walkClassExpression(expression);
1385
- break;
1386
- case "ConditionalExpression":
1387
- this.walkConditionalExpression(expression);
1388
- break;
1389
- case "FunctionExpression":
1390
- this.walkFunctionExpression(expression);
1391
- break;
1392
- case "Identifier":
1393
- this.walkIdentifier(expression);
1394
- break;
1395
- case "LogicalExpression":
1396
- this.walkLogicalExpression(expression);
1397
- break;
1398
- case "MemberExpression":
1399
- this.walkMemberExpression(expression);
1400
- break;
1401
- case "NewExpression":
1402
- this.walkNewExpression(expression);
1403
- break;
1404
- case "ObjectExpression":
1405
- this.walkObjectExpression(expression);
1406
- break;
1407
- case "SequenceExpression":
1408
- this.walkSequenceExpression(expression);
1409
- break;
1410
- case "SpreadElement":
1411
- this.walkSpreadElement(expression);
1412
- break;
1413
- case "TaggedTemplateExpression":
1414
- this.walkTaggedTemplateExpression(expression);
1415
- break;
1416
- case "TemplateLiteral":
1417
- this.walkTemplateLiteral(expression);
1418
- break;
1419
- case "ThisExpression":
1420
- this.walkThisExpression(expression);
1421
- break;
1422
- case "UnaryExpression":
1423
- this.walkUnaryExpression(expression);
1424
- break;
1425
- case "UpdateExpression":
1426
- this.walkUpdateExpression(expression);
1427
- break;
1428
- case "YieldExpression":
1429
- this.walkYieldExpression(expression);
1430
- break;
1431
- }
1432
- }
1433
-
1434
- walkAwaitExpression(expression) {
1435
- this.walkExpression(expression.argument);
1436
- }
1437
-
1438
- walkArrayExpression(expression) {
1439
- if (expression.elements) this.walkExpressions(expression.elements);
1440
- }
1441
-
1442
- walkSpreadElement(expression) {
1443
- if (expression.argument) this.walkExpression(expression.argument);
1444
- }
1445
-
1446
- walkObjectExpression(expression) {
1447
- for (
1448
- let propIndex = 0, len = expression.properties.length;
1449
- propIndex < len;
1450
- propIndex++
1451
- ) {
1452
- const prop = expression.properties[propIndex];
1453
- if (prop.type === "SpreadElement") {
1454
- this.walkExpression(prop.argument);
1455
- continue;
1456
- }
1457
- if (prop.computed) this.walkExpression(prop.key);
1458
- if (prop.shorthand) this.scope.inShorthand = true;
1459
- this.walkExpression(prop.value);
1460
- if (prop.shorthand) this.scope.inShorthand = false;
1461
- }
1462
- }
1463
-
1464
- walkFunctionExpression(expression) {
1465
- for (const param of expression.params) this.walkPattern(param);
1466
- this.inScope(expression.params, () => {
1467
- this.scope.topLevelScope = false;
1468
- if (expression.body.type === "BlockStatement") {
1469
- this.detectStrictMode(expression.body.body);
1470
- this.prewalkStatement(expression.body);
1471
- this.walkStatement(expression.body);
1472
- } else {
1473
- this.walkExpression(expression.body);
1474
- }
1475
- });
1476
- }
1477
-
1478
- walkArrowFunctionExpression(expression) {
1479
- for (const param of expression.params) this.walkPattern(param);
1480
- this.inScope(expression.params, () => {
1481
- if (expression.body.type === "BlockStatement") {
1482
- this.detectStrictMode(expression.body.body);
1483
- this.prewalkStatement(expression.body);
1484
- this.walkStatement(expression.body);
1485
- } else {
1486
- this.walkExpression(expression.body);
1487
- }
1488
- });
1489
- }
1490
-
1491
- walkSequenceExpression(expression) {
1492
- if (expression.expressions) this.walkExpressions(expression.expressions);
1493
- }
1494
-
1495
- walkUpdateExpression(expression) {
1496
- this.walkExpression(expression.argument);
1497
- }
1498
-
1499
- walkUnaryExpression(expression) {
1500
- if (expression.operator === "typeof") {
1501
- const exprName = this.getNameForExpression(expression.argument);
1502
- if (exprName && exprName.free) {
1503
- const hook = this.hooks.typeof.get(exprName.name);
1504
- if (hook !== undefined) {
1505
- const result = hook.call(expression);
1506
- if (result === true) return;
1507
- }
1508
- }
1509
- }
1510
- this.walkExpression(expression.argument);
1511
- }
1512
-
1513
- walkLeftRightExpression(expression) {
1514
- this.walkExpression(expression.left);
1515
- this.walkExpression(expression.right);
1516
- }
1517
-
1518
- walkBinaryExpression(expression) {
1519
- this.walkLeftRightExpression(expression);
1520
- }
1521
-
1522
- walkLogicalExpression(expression) {
1523
- this.walkLeftRightExpression(expression);
1524
- }
1525
-
1526
- walkAssignmentExpression(expression) {
1527
- const renameIdentifier = this.getRenameIdentifier(expression.right);
1528
- if (expression.left.type === "Identifier" && renameIdentifier) {
1529
- const hook = this.hooks.canRename.get(renameIdentifier);
1530
- if (hook !== undefined && hook.call(expression.right)) {
1531
- // renaming "a = b;"
1532
- const hook = this.hooks.rename.get(renameIdentifier);
1533
- if (hook === undefined || !hook.call(expression.right)) {
1534
- this.scope.renames.set(expression.left.name, renameIdentifier);
1535
- this.scope.definitions.delete(expression.left.name);
1536
- }
1537
- return;
1538
- }
1539
- }
1540
- if (expression.left.type === "Identifier") {
1541
- const assignedHook = this.hooks.assigned.get(expression.left.name);
1542
- if (assignedHook === undefined || !assignedHook.call(expression)) {
1543
- this.walkExpression(expression.right);
1544
- }
1545
- this.scope.renames.set(expression.left.name, null);
1546
- const assignHook = this.hooks.assign.get(expression.left.name);
1547
- if (assignHook === undefined || !assignHook.call(expression)) {
1548
- this.walkExpression(expression.left);
1549
- }
1550
- return;
1551
- }
1552
- this.walkExpression(expression.right);
1553
- this.walkPattern(expression.left);
1554
- this.enterPattern(expression.left, (name, decl) => {
1555
- this.scope.renames.set(name, null);
1556
- });
1557
- }
1558
-
1559
- walkConditionalExpression(expression) {
1560
- const result = this.hooks.expressionConditionalOperator.call(expression);
1561
- if (result === undefined) {
1562
- this.walkExpression(expression.test);
1563
- this.walkExpression(expression.consequent);
1564
- if (expression.alternate) this.walkExpression(expression.alternate);
1565
- } else {
1566
- if (result) this.walkExpression(expression.consequent);
1567
- else if (expression.alternate) this.walkExpression(expression.alternate);
1568
- }
1569
- }
1570
-
1571
- walkNewExpression(expression) {
1572
- const callee = this.evaluateExpression(expression.callee);
1573
- if (callee.isIdentifier()) {
1574
- const hook = this.hooks.new.get(callee.identifier);
1575
- if (hook !== undefined) {
1576
- const result = hook.call(expression);
1577
- if (result === true) {
1578
- return;
1579
- }
1580
- }
1581
- }
1582
-
1583
- this.walkExpression(expression.callee);
1584
- if (expression.arguments) this.walkExpressions(expression.arguments);
1585
- }
1586
-
1587
- walkYieldExpression(expression) {
1588
- if (expression.argument) this.walkExpression(expression.argument);
1589
- }
1590
-
1591
- walkTemplateLiteral(expression) {
1592
- if (expression.expressions) this.walkExpressions(expression.expressions);
1593
- }
1594
-
1595
- walkTaggedTemplateExpression(expression) {
1596
- if (expression.tag) this.walkExpression(expression.tag);
1597
- if (expression.quasi && expression.quasi.expressions)
1598
- this.walkExpressions(expression.quasi.expressions);
1599
- }
1600
-
1601
- walkClassExpression(expression) {
1602
- this.walkClass(expression);
1603
- }
1604
-
1605
- walkCallExpression(expression) {
1606
- let result;
1607
-
1608
- const walkIIFE = (functionExpression, options, currentThis) => {
1609
- const renameArgOrThis = argOrThis => {
1610
- const renameIdentifier = this.getRenameIdentifier(argOrThis);
1611
- if (renameIdentifier) {
1612
- const hook = this.hooks.canRename.get(renameIdentifier);
1613
- if (hook !== undefined && hook.call(argOrThis)) {
1614
- const hook = this.hooks.rename.get(renameIdentifier);
1615
- if (hook === undefined || !hook.call(argOrThis))
1616
- return renameIdentifier;
1617
- }
1618
- }
1619
- this.walkExpression(argOrThis);
1620
- };
1621
- const params = functionExpression.params;
1622
- const renameThis = currentThis
1623
- ? renameArgOrThis.call(this, currentThis)
1624
- : null;
1625
- const args = options.map(renameArgOrThis);
1626
- this.inScope(params.filter((identifier, idx) => !args[idx]), () => {
1627
- if (renameThis) {
1628
- this.scope.renames.set("this", renameThis);
1629
- }
1630
- for (let i = 0; i < args.length; i++) {
1631
- const param = args[i];
1632
- if (!param) continue;
1633
- if (!params[i] || params[i].type !== "Identifier") continue;
1634
- this.scope.renames.set(params[i].name, param);
1635
- }
1636
- if (functionExpression.body.type === "BlockStatement") {
1637
- this.prewalkStatement(functionExpression.body);
1638
- this.walkStatement(functionExpression.body);
1639
- } else this.walkExpression(functionExpression.body);
1640
- });
1641
- };
1642
- if (
1643
- expression.callee.type === "MemberExpression" &&
1644
- expression.callee.object.type === "FunctionExpression" &&
1645
- !expression.callee.computed &&
1646
- (expression.callee.property.name === "call" ||
1647
- expression.callee.property.name === "bind") &&
1648
- expression.arguments &&
1649
- expression.arguments.length > 0
1650
- ) {
1651
- // (function(...) { }.call/bind(?, ...))
1652
- walkIIFE.call(
1653
- this,
1654
- expression.callee.object,
1655
- expression.arguments.slice(1),
1656
- expression.arguments[0]
1657
- );
1658
- } else if (
1659
- expression.callee.type === "FunctionExpression" &&
1660
- expression.arguments
1661
- ) {
1662
- // (function(...) { }(...))
1663
- walkIIFE.call(this, expression.callee, expression.arguments);
1664
- } else if (expression.callee.type === "Import") {
1665
- result = this.hooks.importCall.call(expression);
1666
- if (result === true) return;
1667
-
1668
- if (expression.arguments) this.walkExpressions(expression.arguments);
1669
- } else {
1670
- const callee = this.evaluateExpression(expression.callee);
1671
- if (callee.isIdentifier()) {
1672
- const callHook = this.hooks.call.get(callee.identifier);
1673
- if (callHook !== undefined) {
1674
- result = callHook.call(expression);
1675
- if (result === true) return;
1676
- }
1677
- let identifier = callee.identifier.replace(/\.[^.]+$/, "");
1678
- if (identifier !== callee.identifier) {
1679
- const callAnyHook = this.hooks.callAnyMember.get(identifier);
1680
- if (callAnyHook !== undefined) {
1681
- result = callAnyHook.call(expression);
1682
- if (result === true) return;
1683
- }
1684
- }
1685
- }
1686
-
1687
- if (expression.callee) this.walkExpression(expression.callee);
1688
- if (expression.arguments) this.walkExpressions(expression.arguments);
1689
- }
1690
- }
1691
-
1692
- walkMemberExpression(expression) {
1693
- const exprName = this.getNameForExpression(expression);
1694
- if (exprName && exprName.free) {
1695
- const expressionHook = this.hooks.expression.get(exprName.name);
1696
- if (expressionHook !== undefined) {
1697
- const result = expressionHook.call(expression);
1698
- if (result === true) return;
1699
- }
1700
- const expressionAnyMemberHook = this.hooks.expressionAnyMember.get(
1701
- exprName.nameGeneral
1702
- );
1703
- if (expressionAnyMemberHook !== undefined) {
1704
- const result = expressionAnyMemberHook.call(expression);
1705
- if (result === true) return;
1706
- }
1707
- }
1708
- this.walkExpression(expression.object);
1709
- if (expression.computed === true) this.walkExpression(expression.property);
1710
- }
1711
-
1712
- walkThisExpression(expression) {
1713
- const expressionHook = this.hooks.expression.get("this");
1714
- if (expressionHook !== undefined) {
1715
- expressionHook.call(expression);
1716
- }
1717
- }
1718
-
1719
- walkIdentifier(expression) {
1720
- if (!this.scope.definitions.has(expression.name)) {
1721
- const hook = this.hooks.expression.get(
1722
- this.scope.renames.get(expression.name) || expression.name
1723
- );
1724
- if (hook !== undefined) {
1725
- const result = hook.call(expression);
1726
- if (result === true) return;
1727
- }
1728
- }
1729
- }
1730
-
1731
- inScope(params, fn) {
1732
- const oldScope = this.scope;
1733
- this.scope = {
1734
- topLevelScope: oldScope.topLevelScope,
1735
- inTry: false,
1736
- inShorthand: false,
1737
- isStrict: oldScope.isStrict,
1738
- definitions: oldScope.definitions.createChild(),
1739
- renames: oldScope.renames.createChild()
1740
- };
1741
-
1742
- this.scope.renames.set("this", null);
1743
-
1744
- for (
1745
- let paramIndex = 0, len = params.length;
1746
- paramIndex < len;
1747
- paramIndex++
1748
- ) {
1749
- const param = params[paramIndex];
1750
-
1751
- if (typeof param !== "string") {
1752
- this.enterPattern(param, param => {
1753
- this.scope.renames.set(param, null);
1754
- this.scope.definitions.add(param);
1755
- });
1756
- } else if (param) {
1757
- this.scope.renames.set(param, null);
1758
- this.scope.definitions.add(param);
1759
- }
1760
- }
1761
-
1762
- fn();
1763
- this.scope = oldScope;
1764
- }
1765
-
1766
- detectStrictMode(statements) {
1767
- const isStrict =
1768
- statements.length >= 1 &&
1769
- statements[0].type === "ExpressionStatement" &&
1770
- statements[0].expression.type === "Literal" &&
1771
- statements[0].expression.value === "use strict";
1772
- if (isStrict) {
1773
- this.scope.isStrict = true;
1774
- }
1775
- }
1776
-
1777
- enterPattern(pattern, onIdent) {
1778
- if (!pattern) return;
1779
- switch (pattern.type) {
1780
- case "ArrayPattern":
1781
- this.enterArrayPattern(pattern, onIdent);
1782
- break;
1783
- case "AssignmentPattern":
1784
- this.enterAssignmentPattern(pattern, onIdent);
1785
- break;
1786
- case "Identifier":
1787
- this.enterIdentifier(pattern, onIdent);
1788
- break;
1789
- case "ObjectPattern":
1790
- this.enterObjectPattern(pattern, onIdent);
1791
- break;
1792
- case "RestElement":
1793
- this.enterRestElement(pattern, onIdent);
1794
- break;
1795
- }
1796
- }
1797
-
1798
- enterIdentifier(pattern, onIdent) {
1799
- onIdent(pattern.name, pattern);
1800
- }
1801
-
1802
- enterObjectPattern(pattern, onIdent) {
1803
- for (
1804
- let propIndex = 0, len = pattern.properties.length;
1805
- propIndex < len;
1806
- propIndex++
1807
- ) {
1808
- const prop = pattern.properties[propIndex];
1809
- this.enterPattern(prop.value, onIdent);
1810
- }
1811
- }
1812
-
1813
- enterArrayPattern(pattern, onIdent) {
1814
- for (
1815
- let elementIndex = 0, len = pattern.elements.length;
1816
- elementIndex < len;
1817
- elementIndex++
1818
- ) {
1819
- const element = pattern.elements[elementIndex];
1820
- this.enterPattern(element, onIdent);
1821
- }
1822
- }
1823
-
1824
- enterRestElement(pattern, onIdent) {
1825
- this.enterPattern(pattern.argument, onIdent);
1826
- }
1827
-
1828
- enterAssignmentPattern(pattern, onIdent) {
1829
- this.enterPattern(pattern.left, onIdent);
1830
- }
1831
-
1832
- evaluateExpression(expression) {
1833
- try {
1834
- const hook = this.hooks.evaluate.get(expression.type);
1835
- if (hook !== undefined) {
1836
- const result = hook.call(expression);
1837
- if (result !== undefined) return result;
1838
- }
1839
- } catch (e) {
1840
- console.warn(e);
1841
- // ignore error
1842
- }
1843
- return new BasicEvaluatedExpression().setRange(expression.range);
1844
- }
1845
-
1846
- parseString(expression) {
1847
- switch (expression.type) {
1848
- case "BinaryExpression":
1849
- if (expression.operator === "+")
1850
- return (
1851
- this.parseString(expression.left) +
1852
- this.parseString(expression.right)
1853
- );
1854
- break;
1855
- case "Literal":
1856
- return expression.value + "";
1857
- }
1858
- throw new Error(
1859
- expression.type + " is not supported as parameter for require"
1860
- );
1861
- }
1862
-
1863
- parseCalculatedString(expression) {
1864
- switch (expression.type) {
1865
- case "BinaryExpression":
1866
- if (expression.operator === "+") {
1867
- const left = this.parseCalculatedString(expression.left);
1868
- const right = this.parseCalculatedString(expression.right);
1869
- if (left.code) {
1870
- return {
1871
- range: left.range,
1872
- value: left.value,
1873
- code: true
1874
- };
1875
- } else if (right.code) {
1876
- return {
1877
- range: [
1878
- left.range[0],
1879
- right.range ? right.range[1] : left.range[1]
1880
- ],
1881
- value: left.value + right.value,
1882
- code: true
1883
- };
1884
- } else {
1885
- return {
1886
- range: [left.range[0], right.range[1]],
1887
- value: left.value + right.value
1888
- };
1889
- }
1890
- }
1891
- break;
1892
- case "ConditionalExpression": {
1893
- const consequent = this.parseCalculatedString(expression.consequent);
1894
- const alternate = this.parseCalculatedString(expression.alternate);
1895
- const items = [];
1896
- if (consequent.conditional) items.push(...consequent.conditional);
1897
- else if (!consequent.code) items.push(consequent);
1898
- else break;
1899
- if (alternate.conditional) items.push(...alternate.conditional);
1900
- else if (!alternate.code) items.push(alternate);
1901
- else break;
1902
- return {
1903
- value: "",
1904
- code: true,
1905
- conditional: items
1906
- };
1907
- }
1908
- case "Literal":
1909
- return {
1910
- range: expression.range,
1911
- value: expression.value + ""
1912
- };
1913
- }
1914
- return {
1915
- value: "",
1916
- code: true
1917
- };
1918
- }
1919
-
1920
- parse(source, initialState) {
1921
- let ast;
1922
- let comments;
1923
- if (typeof source === "object" && source !== null) {
1924
- ast = source;
1925
- comments = source.comments;
1926
- } else {
1927
- comments = [];
1928
- ast = Parser.parse(source, {
1929
- sourceType: this.sourceType,
1930
- onComment: comments
1931
- });
1932
- }
1933
-
1934
- const oldScope = this.scope;
1935
- const oldState = this.state;
1936
- const oldComments = this.comments;
1937
- this.scope = {
1938
- topLevelScope: true,
1939
- inTry: false,
1940
- inShorthand: false,
1941
- isStrict: false,
1942
- definitions: new StackedSetMap(),
1943
- renames: new StackedSetMap()
1944
- };
1945
- const state = (this.state = initialState || {});
1946
- this.comments = comments;
1947
- if (this.hooks.program.call(ast, comments) === undefined) {
1948
- this.detectStrictMode(ast.body);
1949
- this.prewalkStatements(ast.body);
1950
- this.walkStatements(ast.body);
1951
- }
1952
- this.scope = oldScope;
1953
- this.state = oldState;
1954
- this.comments = oldComments;
1955
- return state;
1956
- }
1957
-
1958
- evaluate(source) {
1959
- const ast = Parser.parse("(" + source + ")", {
1960
- sourceType: this.sourceType,
1961
- locations: false
1962
- });
1963
- if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement")
1964
- throw new Error("evaluate: Source is not a expression");
1965
- return this.evaluateExpression(ast.body[0].expression);
1966
- }
1967
-
1968
- getComments(range) {
1969
- return this.comments.filter(
1970
- comment => comment.range[0] >= range[0] && comment.range[1] <= range[1]
1971
- );
1972
- }
1973
-
1974
- getCommentOptions(range) {
1975
- const comments = this.getComments(range);
1976
- if (comments.length === 0) return null;
1977
- const options = comments.map(comment => {
1978
- try {
1979
- let val = vm.runInNewContext(
1980
- `(function(){return {${comment.value}};})()`
1981
- );
1982
- return val;
1983
- } catch (e) {
1984
- return {};
1985
- }
1986
- });
1987
- return options.reduce((o, i) => Object.assign(o, i), {});
1988
- }
1989
-
1990
- getNameForExpression(expression) {
1991
- let expr = expression;
1992
- const exprName = [];
1993
- while (
1994
- expr.type === "MemberExpression" &&
1995
- expr.property.type === (expr.computed ? "Literal" : "Identifier")
1996
- ) {
1997
- exprName.push(expr.computed ? expr.property.value : expr.property.name);
1998
- expr = expr.object;
1999
- }
2000
- let free;
2001
- if (expr.type === "Identifier") {
2002
- free = !this.scope.definitions.has(expr.name);
2003
- exprName.push(this.scope.renames.get(expr.name) || expr.name);
2004
- } else if (
2005
- expr.type === "ThisExpression" &&
2006
- this.scope.renames.get("this")
2007
- ) {
2008
- free = true;
2009
- exprName.push(this.scope.renames.get("this"));
2010
- } else if (expr.type === "ThisExpression") {
2011
- free = this.scope.topLevelScope;
2012
- exprName.push("this");
2013
- } else {
2014
- return null;
2015
- }
2016
- let prefix = "";
2017
- for (let i = exprName.length - 1; i >= 2; i--) prefix += exprName[i] + ".";
2018
- if (exprName.length > 1) prefix += exprName[1];
2019
- const name = prefix ? prefix + "." + exprName[0] : exprName[0];
2020
- const nameGeneral = prefix;
2021
- return {
2022
- name,
2023
- nameGeneral,
2024
- free
2025
- };
2026
- }
2027
-
2028
- static parse(code, options) {
2029
- const type = options ? options.sourceType : "module";
2030
- const parserOptions = Object.assign(
2031
- Object.create(null),
2032
- defaultParserOptions,
2033
- options
2034
- );
2035
-
2036
- if (type === "auto") {
2037
- parserOptions.sourceType = "module";
2038
- }
2039
-
2040
- let ast;
2041
- let error;
2042
- let threw = false;
2043
- try {
2044
- ast = acorn.parse(code, parserOptions);
2045
- } catch (e) {
2046
- error = e;
2047
- threw = true;
2048
- }
2049
-
2050
- if (threw && type === "auto") {
2051
- parserOptions.sourceType = "script";
2052
- if (Array.isArray(parserOptions.onComment)) {
2053
- parserOptions.onComment.length = 0;
2054
- }
2055
- try {
2056
- ast = acorn.parse(code, parserOptions);
2057
- threw = false;
2058
- } catch (e) {
2059
- threw = true;
2060
- }
2061
- }
2062
-
2063
- if (threw) {
2064
- throw error;
2065
- }
2066
-
2067
- return ast;
2068
- }
2069
- }
2070
-
2071
- module.exports = Parser;
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ "use strict";
6
+
7
+ // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
8
+
9
+ const acorn = require("acorn-dynamic-import").default;
10
+ const { Tapable, SyncBailHook } = require("tapable");
11
+ const HookMap = require("tapable/lib/HookMap");
12
+ const vm = require("vm");
13
+ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
14
+ const StackedSetMap = require("./util/StackedSetMap");
15
+ const TrackingSet = require("./util/TrackingSet");
16
+
17
+ const joinRanges = (startRange, endRange) => {
18
+ if (!endRange) return startRange;
19
+ if (!startRange) return endRange;
20
+ return [startRange[0], endRange[1]];
21
+ };
22
+
23
+ const defaultParserOptions = {
24
+ ranges: true,
25
+ locations: true,
26
+ ecmaVersion: 2018,
27
+ sourceType: "module",
28
+ onComment: null,
29
+ plugins: {
30
+ dynamicImport: true
31
+ }
32
+ };
33
+
34
+ class Parser extends Tapable {
35
+ constructor(options, sourceType = "auto") {
36
+ super();
37
+ this.hooks = {
38
+ evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])),
39
+ evaluate: new HookMap(() => new SyncBailHook(["expression"])),
40
+ evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])),
41
+ evaluateDefinedIdentifier: new HookMap(
42
+ () => new SyncBailHook(["expression"])
43
+ ),
44
+ evaluateCallExpressionMember: new HookMap(
45
+ () => new SyncBailHook(["expression", "param"])
46
+ ),
47
+ statement: new SyncBailHook(["statement"]),
48
+ statementIf: new SyncBailHook(["statement"]),
49
+ label: new HookMap(() => new SyncBailHook(["statement"])),
50
+ import: new SyncBailHook(["statement", "source"]),
51
+ importSpecifier: new SyncBailHook([
52
+ "statement",
53
+ "source",
54
+ "exportName",
55
+ "identifierName"
56
+ ]),
57
+ export: new SyncBailHook(["statement"]),
58
+ exportImport: new SyncBailHook(["statement", "source"]),
59
+ exportDeclaration: new SyncBailHook(["statement", "declaration"]),
60
+ exportExpression: new SyncBailHook(["statement", "declaration"]),
61
+ exportSpecifier: new SyncBailHook([
62
+ "statement",
63
+ "identifierName",
64
+ "exportName",
65
+ "index"
66
+ ]),
67
+ exportImportSpecifier: new SyncBailHook([
68
+ "statement",
69
+ "source",
70
+ "identifierName",
71
+ "exportName",
72
+ "index"
73
+ ]),
74
+ varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])),
75
+ varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])),
76
+ varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])),
77
+ varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])),
78
+ canRename: new HookMap(() => new SyncBailHook(["initExpression"])),
79
+ rename: new HookMap(() => new SyncBailHook(["initExpression"])),
80
+ assigned: new HookMap(() => new SyncBailHook(["expression"])),
81
+ assign: new HookMap(() => new SyncBailHook(["expression"])),
82
+ typeof: new HookMap(() => new SyncBailHook(["expression"])),
83
+ importCall: new SyncBailHook(["expression"]),
84
+ call: new HookMap(() => new SyncBailHook(["expression"])),
85
+ callAnyMember: new HookMap(() => new SyncBailHook(["expression"])),
86
+ new: new HookMap(() => new SyncBailHook(["expression"])),
87
+ expression: new HookMap(() => new SyncBailHook(["expression"])),
88
+ expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])),
89
+ expressionConditionalOperator: new SyncBailHook(["expression"]),
90
+ program: new SyncBailHook(["ast", "comments"])
91
+ };
92
+ const HOOK_MAP_COMPAT_CONFIG = {
93
+ evaluateTypeof: /^evaluate typeof (.+)$/,
94
+ evaluateIdentifier: /^evaluate Identifier (.+)$/,
95
+ evaluateDefinedIdentifier: /^evaluate defined Identifier (.+)$/,
96
+ evaluateCallExpressionMember: /^evaluate CallExpression .(.+)$/,
97
+ evaluate: /^evaluate (.+)$/,
98
+ label: /^label (.+)$/,
99
+ varDeclarationLet: /^var-let (.+)$/,
100
+ varDeclarationConst: /^var-const (.+)$/,
101
+ varDeclarationVar: /^var-var (.+)$/,
102
+ varDeclaration: /^var (.+)$/,
103
+ canRename: /^can-rename (.+)$/,
104
+ rename: /^rename (.+)$/,
105
+ typeof: /^typeof (.+)$/,
106
+ assigned: /^assigned (.+)$/,
107
+ assign: /^assign (.+)$/,
108
+ callAnyMember: /^call (.+)\.\*$/,
109
+ call: /^call (.+)$/,
110
+ new: /^new (.+)$/,
111
+ expressionConditionalOperator: /^expression \?:$/,
112
+ expressionAnyMember: /^expression (.+)\.\*$/,
113
+ expression: /^expression (.+)$/
114
+ };
115
+ this._pluginCompat.tap("Parser", options => {
116
+ for (const name of Object.keys(HOOK_MAP_COMPAT_CONFIG)) {
117
+ const regexp = HOOK_MAP_COMPAT_CONFIG[name];
118
+ const match = regexp.exec(options.name);
119
+ if (match) {
120
+ if (match[1])
121
+ this.hooks[name].tap(
122
+ match[1],
123
+ options.fn.name || "unnamed compat plugin",
124
+ options.fn.bind(this)
125
+ );
126
+ else
127
+ this.hooks[name].tap(
128
+ options.fn.name || "unnamed compat plugin",
129
+ options.fn.bind(this)
130
+ );
131
+ return true;
132
+ }
133
+ }
134
+ });
135
+ this.options = options;
136
+ this.sourceType = sourceType;
137
+ this.scope = undefined;
138
+ this.state = undefined;
139
+ this.comments = undefined;
140
+ this.initializeEvaluating();
141
+ }
142
+
143
+ initializeEvaluating() {
144
+ this.hooks.evaluate.for("Literal").tap("Parser", expr => {
145
+ switch (typeof expr.value) {
146
+ case "number":
147
+ return new BasicEvaluatedExpression()
148
+ .setNumber(expr.value)
149
+ .setRange(expr.range);
150
+ case "string":
151
+ return new BasicEvaluatedExpression()
152
+ .setString(expr.value)
153
+ .setRange(expr.range);
154
+ case "boolean":
155
+ return new BasicEvaluatedExpression()
156
+ .setBoolean(expr.value)
157
+ .setRange(expr.range);
158
+ }
159
+ if (expr.value === null)
160
+ return new BasicEvaluatedExpression().setNull().setRange(expr.range);
161
+ if (expr.value instanceof RegExp)
162
+ return new BasicEvaluatedExpression()
163
+ .setRegExp(expr.value)
164
+ .setRange(expr.range);
165
+ });
166
+ this.hooks.evaluate.for("LogicalExpression").tap("Parser", expr => {
167
+ let left;
168
+ let leftAsBool;
169
+ let right;
170
+ if (expr.operator === "&&") {
171
+ left = this.evaluateExpression(expr.left);
172
+ leftAsBool = left && left.asBool();
173
+ if (leftAsBool === false) return left.setRange(expr.range);
174
+ if (leftAsBool !== true) return;
175
+ right = this.evaluateExpression(expr.right);
176
+ return right.setRange(expr.range);
177
+ } else if (expr.operator === "||") {
178
+ left = this.evaluateExpression(expr.left);
179
+ leftAsBool = left && left.asBool();
180
+ if (leftAsBool === true) return left.setRange(expr.range);
181
+ if (leftAsBool !== false) return;
182
+ right = this.evaluateExpression(expr.right);
183
+ return right.setRange(expr.range);
184
+ }
185
+ });
186
+ this.hooks.evaluate.for("BinaryExpression").tap("Parser", expr => {
187
+ let left;
188
+ let right;
189
+ let res;
190
+ if (expr.operator === "+") {
191
+ left = this.evaluateExpression(expr.left);
192
+ right = this.evaluateExpression(expr.right);
193
+ if (!left || !right) return;
194
+ res = new BasicEvaluatedExpression();
195
+ if (left.isString()) {
196
+ if (right.isString()) {
197
+ res.setString(left.string + right.string);
198
+ } else if (right.isNumber()) {
199
+ res.setString(left.string + right.number);
200
+ } else if (
201
+ right.isWrapped() &&
202
+ right.prefix &&
203
+ right.prefix.isString()
204
+ ) {
205
+ res.setWrapped(
206
+ new BasicEvaluatedExpression()
207
+ .setString(left.string + right.prefix.string)
208
+ .setRange(joinRanges(left.range, right.prefix.range)),
209
+ right.postfix
210
+ );
211
+ } else if (right.isWrapped()) {
212
+ res.setWrapped(
213
+ new BasicEvaluatedExpression()
214
+ .setString(left.string)
215
+ .setRange(left.range),
216
+ right.postfix
217
+ );
218
+ } else {
219
+ res.setWrapped(left, null);
220
+ }
221
+ } else if (left.isNumber()) {
222
+ if (right.isString()) {
223
+ res.setString(left.number + right.string);
224
+ } else if (right.isNumber()) {
225
+ res.setNumber(left.number + right.number);
226
+ }
227
+ } else if (left.isWrapped()) {
228
+ if (left.postfix && left.postfix.isString() && right.isString()) {
229
+ res.setWrapped(
230
+ left.prefix,
231
+ new BasicEvaluatedExpression()
232
+ .setString(left.postfix.string + right.string)
233
+ .setRange(joinRanges(left.postfix.range, right.range))
234
+ );
235
+ } else if (
236
+ left.postfix &&
237
+ left.postfix.isString() &&
238
+ right.isNumber()
239
+ ) {
240
+ res.setWrapped(
241
+ left.prefix,
242
+ new BasicEvaluatedExpression()
243
+ .setString(left.postfix.string + right.number)
244
+ .setRange(joinRanges(left.postfix.range, right.range))
245
+ );
246
+ } else if (right.isString()) {
247
+ res.setWrapped(left.prefix, right);
248
+ } else if (right.isNumber()) {
249
+ res.setWrapped(
250
+ left.prefix,
251
+ new BasicEvaluatedExpression()
252
+ .setString(right.number + "")
253
+ .setRange(right.range)
254
+ );
255
+ } else {
256
+ res.setWrapped(left.prefix, new BasicEvaluatedExpression());
257
+ }
258
+ } else {
259
+ if (right.isString()) {
260
+ res.setWrapped(null, right);
261
+ }
262
+ }
263
+ res.setRange(expr.range);
264
+ return res;
265
+ } else if (expr.operator === "-") {
266
+ left = this.evaluateExpression(expr.left);
267
+ right = this.evaluateExpression(expr.right);
268
+ if (!left || !right) return;
269
+ if (!left.isNumber() || !right.isNumber()) return;
270
+ res = new BasicEvaluatedExpression();
271
+ res.setNumber(left.number - right.number);
272
+ res.setRange(expr.range);
273
+ return res;
274
+ } else if (expr.operator === "*") {
275
+ left = this.evaluateExpression(expr.left);
276
+ right = this.evaluateExpression(expr.right);
277
+ if (!left || !right) return;
278
+ if (!left.isNumber() || !right.isNumber()) return;
279
+ res = new BasicEvaluatedExpression();
280
+ res.setNumber(left.number * right.number);
281
+ res.setRange(expr.range);
282
+ return res;
283
+ } else if (expr.operator === "/") {
284
+ left = this.evaluateExpression(expr.left);
285
+ right = this.evaluateExpression(expr.right);
286
+ if (!left || !right) return;
287
+ if (!left.isNumber() || !right.isNumber()) return;
288
+ res = new BasicEvaluatedExpression();
289
+ res.setNumber(left.number / right.number);
290
+ res.setRange(expr.range);
291
+ return res;
292
+ } else if (expr.operator === "**") {
293
+ left = this.evaluateExpression(expr.left);
294
+ right = this.evaluateExpression(expr.right);
295
+ if (!left || !right) return;
296
+ if (!left.isNumber() || !right.isNumber()) return;
297
+ res = new BasicEvaluatedExpression();
298
+ res.setNumber(Math.pow(left.number, right.number));
299
+ res.setRange(expr.range);
300
+ return res;
301
+ } else if (expr.operator === "==" || expr.operator === "===") {
302
+ left = this.evaluateExpression(expr.left);
303
+ right = this.evaluateExpression(expr.right);
304
+ if (!left || !right) return;
305
+ res = new BasicEvaluatedExpression();
306
+ res.setRange(expr.range);
307
+ if (left.isString() && right.isString()) {
308
+ return res.setBoolean(left.string === right.string);
309
+ } else if (left.isNumber() && right.isNumber()) {
310
+ return res.setBoolean(left.number === right.number);
311
+ } else if (left.isBoolean() && right.isBoolean()) {
312
+ return res.setBoolean(left.bool === right.bool);
313
+ }
314
+ } else if (expr.operator === "!=" || expr.operator === "!==") {
315
+ left = this.evaluateExpression(expr.left);
316
+ right = this.evaluateExpression(expr.right);
317
+ if (!left || !right) return;
318
+ res = new BasicEvaluatedExpression();
319
+ res.setRange(expr.range);
320
+ if (left.isString() && right.isString()) {
321
+ return res.setBoolean(left.string !== right.string);
322
+ } else if (left.isNumber() && right.isNumber()) {
323
+ return res.setBoolean(left.number !== right.number);
324
+ } else if (left.isBoolean() && right.isBoolean()) {
325
+ return res.setBoolean(left.bool !== right.bool);
326
+ }
327
+ } else if (expr.operator === "&") {
328
+ left = this.evaluateExpression(expr.left);
329
+ right = this.evaluateExpression(expr.right);
330
+ if (!left || !right) return;
331
+ if (!left.isNumber() || !right.isNumber()) return;
332
+ res = new BasicEvaluatedExpression();
333
+ res.setNumber(left.number & right.number);
334
+ res.setRange(expr.range);
335
+ return res;
336
+ } else if (expr.operator === "|") {
337
+ left = this.evaluateExpression(expr.left);
338
+ right = this.evaluateExpression(expr.right);
339
+ if (!left || !right) return;
340
+ if (!left.isNumber() || !right.isNumber()) return;
341
+ res = new BasicEvaluatedExpression();
342
+ res.setNumber(left.number | right.number);
343
+ res.setRange(expr.range);
344
+ return res;
345
+ } else if (expr.operator === "^") {
346
+ left = this.evaluateExpression(expr.left);
347
+ right = this.evaluateExpression(expr.right);
348
+ if (!left || !right) return;
349
+ if (!left.isNumber() || !right.isNumber()) return;
350
+ res = new BasicEvaluatedExpression();
351
+ res.setNumber(left.number ^ right.number);
352
+ res.setRange(expr.range);
353
+ return res;
354
+ } else if (expr.operator === ">>>") {
355
+ left = this.evaluateExpression(expr.left);
356
+ right = this.evaluateExpression(expr.right);
357
+ if (!left || !right) return;
358
+ if (!left.isNumber() || !right.isNumber()) return;
359
+ res = new BasicEvaluatedExpression();
360
+ res.setNumber(left.number >>> right.number);
361
+ res.setRange(expr.range);
362
+ return res;
363
+ } else if (expr.operator === ">>") {
364
+ left = this.evaluateExpression(expr.left);
365
+ right = this.evaluateExpression(expr.right);
366
+ if (!left || !right) return;
367
+ if (!left.isNumber() || !right.isNumber()) return;
368
+ res = new BasicEvaluatedExpression();
369
+ res.setNumber(left.number >> right.number);
370
+ res.setRange(expr.range);
371
+ return res;
372
+ } else if (expr.operator === "<<") {
373
+ left = this.evaluateExpression(expr.left);
374
+ right = this.evaluateExpression(expr.right);
375
+ if (!left || !right) return;
376
+ if (!left.isNumber() || !right.isNumber()) return;
377
+ res = new BasicEvaluatedExpression();
378
+ res.setNumber(left.number << right.number);
379
+ res.setRange(expr.range);
380
+ return res;
381
+ }
382
+ });
383
+ this.hooks.evaluate.for("UnaryExpression").tap("Parser", expr => {
384
+ if (expr.operator === "typeof") {
385
+ let res;
386
+ let name;
387
+ if (expr.argument.type === "Identifier") {
388
+ name =
389
+ this.scope.renames.get(expr.argument.name) || expr.argument.name;
390
+ if (!this.scope.definitions.has(name)) {
391
+ const hook = this.hooks.evaluateTypeof.get(name);
392
+ if (hook !== undefined) {
393
+ res = hook.call(expr);
394
+ if (res !== undefined) return res;
395
+ }
396
+ }
397
+ }
398
+ if (expr.argument.type === "MemberExpression") {
399
+ const exprName = this.getNameForExpression(expr.argument);
400
+ if (exprName && exprName.free) {
401
+ const hook = this.hooks.evaluateTypeof.get(exprName.name);
402
+ if (hook !== undefined) {
403
+ res = hook.call(expr);
404
+ if (res !== undefined) return res;
405
+ }
406
+ }
407
+ }
408
+ if (expr.argument.type === "FunctionExpression") {
409
+ return new BasicEvaluatedExpression()
410
+ .setString("function")
411
+ .setRange(expr.range);
412
+ }
413
+ const arg = this.evaluateExpression(expr.argument);
414
+ if (arg.isString() || arg.isWrapped())
415
+ return new BasicEvaluatedExpression()
416
+ .setString("string")
417
+ .setRange(expr.range);
418
+ else if (arg.isNumber())
419
+ return new BasicEvaluatedExpression()
420
+ .setString("number")
421
+ .setRange(expr.range);
422
+ else if (arg.isBoolean())
423
+ return new BasicEvaluatedExpression()
424
+ .setString("boolean")
425
+ .setRange(expr.range);
426
+ else if (arg.isArray() || arg.isConstArray() || arg.isRegExp())
427
+ return new BasicEvaluatedExpression()
428
+ .setString("object")
429
+ .setRange(expr.range);
430
+ } else if (expr.operator === "!") {
431
+ const argument = this.evaluateExpression(expr.argument);
432
+ if (!argument) return;
433
+ if (argument.isBoolean()) {
434
+ return new BasicEvaluatedExpression()
435
+ .setBoolean(!argument.bool)
436
+ .setRange(expr.range);
437
+ } else if (argument.isTruthy()) {
438
+ return new BasicEvaluatedExpression()
439
+ .setBoolean(false)
440
+ .setRange(expr.range);
441
+ } else if (argument.isFalsy()) {
442
+ return new BasicEvaluatedExpression()
443
+ .setBoolean(true)
444
+ .setRange(expr.range);
445
+ } else if (argument.isString()) {
446
+ return new BasicEvaluatedExpression()
447
+ .setBoolean(!argument.string)
448
+ .setRange(expr.range);
449
+ } else if (argument.isNumber()) {
450
+ return new BasicEvaluatedExpression()
451
+ .setBoolean(!argument.number)
452
+ .setRange(expr.range);
453
+ }
454
+ } else if (expr.operator === "~") {
455
+ const argument = this.evaluateExpression(expr.argument);
456
+ if (!argument) return;
457
+ if (!argument.isNumber()) return;
458
+ const res = new BasicEvaluatedExpression();
459
+ res.setNumber(~argument.number);
460
+ res.setRange(expr.range);
461
+ return res;
462
+ }
463
+ });
464
+ this.hooks.evaluateTypeof.for("undefined").tap("Parser", expr => {
465
+ return new BasicEvaluatedExpression()
466
+ .setString("undefined")
467
+ .setRange(expr.range);
468
+ });
469
+ this.hooks.evaluate.for("Identifier").tap("Parser", expr => {
470
+ const name = this.scope.renames.get(expr.name) || expr.name;
471
+ if (!this.scope.definitions.has(expr.name)) {
472
+ const hook = this.hooks.evaluateIdentifier.get(name);
473
+ if (hook !== undefined) {
474
+ const result = hook.call(expr);
475
+ if (result) return result;
476
+ }
477
+ return new BasicEvaluatedExpression()
478
+ .setIdentifier(name)
479
+ .setRange(expr.range);
480
+ } else {
481
+ const hook = this.hooks.evaluateDefinedIdentifier.get(name);
482
+ if (hook !== undefined) {
483
+ return hook.call(expr);
484
+ }
485
+ }
486
+ });
487
+ this.hooks.evaluate.for("ThisExpression").tap("Parser", expr => {
488
+ const name = this.scope.renames.get("this");
489
+ if (name) {
490
+ const hook = this.hooks.evaluateIdentifier.get(name);
491
+ if (hook !== undefined) {
492
+ const result = hook.call(expr);
493
+ if (result) return result;
494
+ }
495
+ return new BasicEvaluatedExpression()
496
+ .setIdentifier(name)
497
+ .setRange(expr.range);
498
+ }
499
+ });
500
+ this.hooks.evaluate.for("MemberExpression").tap("Parser", expression => {
501
+ let exprName = this.getNameForExpression(expression);
502
+ if (exprName) {
503
+ if (exprName.free) {
504
+ const hook = this.hooks.evaluateIdentifier.get(exprName.name);
505
+ if (hook !== undefined) {
506
+ const result = hook.call(expression);
507
+ if (result) return result;
508
+ }
509
+ return new BasicEvaluatedExpression()
510
+ .setIdentifier(exprName.name)
511
+ .setRange(expression.range);
512
+ } else {
513
+ const hook = this.hooks.evaluateDefinedIdentifier.get(exprName.name);
514
+ if (hook !== undefined) {
515
+ return hook.call(expression);
516
+ }
517
+ }
518
+ }
519
+ });
520
+ this.hooks.evaluate.for("CallExpression").tap("Parser", expr => {
521
+ if (expr.callee.type !== "MemberExpression") return;
522
+ if (
523
+ expr.callee.property.type !==
524
+ (expr.callee.computed ? "Literal" : "Identifier")
525
+ )
526
+ return;
527
+ const param = this.evaluateExpression(expr.callee.object);
528
+ if (!param) return;
529
+ const property = expr.callee.property.name || expr.callee.property.value;
530
+ const hook = this.hooks.evaluateCallExpressionMember.get(property);
531
+ if (hook !== undefined) {
532
+ return hook.call(expr, param);
533
+ }
534
+ });
535
+ this.hooks.evaluateCallExpressionMember
536
+ .for("replace")
537
+ .tap("Parser", (expr, param) => {
538
+ if (!param.isString()) return;
539
+ if (expr.arguments.length !== 2) return;
540
+ let arg1 = this.evaluateExpression(expr.arguments[0]);
541
+ let arg2 = this.evaluateExpression(expr.arguments[1]);
542
+ if (!arg1.isString() && !arg1.isRegExp()) return;
543
+ arg1 = arg1.regExp || arg1.string;
544
+ if (!arg2.isString()) return;
545
+ arg2 = arg2.string;
546
+ return new BasicEvaluatedExpression()
547
+ .setString(param.string.replace(arg1, arg2))
548
+ .setRange(expr.range);
549
+ });
550
+ ["substr", "substring"].forEach(fn => {
551
+ this.hooks.evaluateCallExpressionMember
552
+ .for(fn)
553
+ .tap("Parser", (expr, param) => {
554
+ if (!param.isString()) return;
555
+ let arg1;
556
+ let result,
557
+ str = param.string;
558
+ switch (expr.arguments.length) {
559
+ case 1:
560
+ arg1 = this.evaluateExpression(expr.arguments[0]);
561
+ if (!arg1.isNumber()) return;
562
+ result = str[fn](arg1.number);
563
+ break;
564
+ case 2: {
565
+ arg1 = this.evaluateExpression(expr.arguments[0]);
566
+ const arg2 = this.evaluateExpression(expr.arguments[1]);
567
+ if (!arg1.isNumber()) return;
568
+ if (!arg2.isNumber()) return;
569
+ result = str[fn](arg1.number, arg2.number);
570
+ break;
571
+ }
572
+ default:
573
+ return;
574
+ }
575
+ return new BasicEvaluatedExpression()
576
+ .setString(result)
577
+ .setRange(expr.range);
578
+ });
579
+ });
580
+
581
+ /**
582
+ * @param {string} kind "cooked" | "raw"
583
+ * @param {any[]} quasis quasis
584
+ * @param {any[]} expressions expressions
585
+ * @return {BasicEvaluatedExpression[]} Simplified template
586
+ */
587
+ const getSimplifiedTemplateResult = (kind, quasis, expressions) => {
588
+ const parts = [];
589
+
590
+ for (let i = 0; i < quasis.length; i++) {
591
+ parts.push(
592
+ new BasicEvaluatedExpression()
593
+ .setString(quasis[i].value[kind])
594
+ .setRange(quasis[i].range)
595
+ );
596
+
597
+ if (i > 0) {
598
+ const prevExpr = parts[parts.length - 2],
599
+ lastExpr = parts[parts.length - 1];
600
+ const expr = this.evaluateExpression(expressions[i - 1]);
601
+ if (!(expr.isString() || expr.isNumber())) continue;
602
+
603
+ prevExpr.setString(
604
+ prevExpr.string +
605
+ (expr.isString() ? expr.string : expr.number) +
606
+ lastExpr.string
607
+ );
608
+ prevExpr.setRange([prevExpr.range[0], lastExpr.range[1]]);
609
+ parts.pop();
610
+ }
611
+ }
612
+ return parts;
613
+ };
614
+
615
+ this.hooks.evaluate.for("TemplateLiteral").tap("Parser", node => {
616
+ const parts = getSimplifiedTemplateResult.call(
617
+ this,
618
+ "cooked",
619
+ node.quasis,
620
+ node.expressions
621
+ );
622
+ if (parts.length === 1) {
623
+ return parts[0].setRange(node.range);
624
+ }
625
+ return new BasicEvaluatedExpression()
626
+ .setTemplateString(parts)
627
+ .setRange(node.range);
628
+ });
629
+ this.hooks.evaluate.for("TaggedTemplateExpression").tap("Parser", node => {
630
+ if (this.evaluateExpression(node.tag).identifier !== "String.raw") return;
631
+ const parts = getSimplifiedTemplateResult.call(
632
+ this,
633
+ "raw",
634
+ node.quasi.quasis,
635
+ node.quasi.expressions
636
+ );
637
+ return new BasicEvaluatedExpression()
638
+ .setTemplateString(parts)
639
+ .setRange(node.range);
640
+ });
641
+
642
+ this.hooks.evaluateCallExpressionMember
643
+ .for("concat")
644
+ .tap("Parser", (expr, param) => {
645
+ if (!param.isString() && !param.isWrapped()) return;
646
+
647
+ let stringSuffix = null;
648
+ let hasUnknownParams = false;
649
+ for (let i = expr.arguments.length - 1; i >= 0; i--) {
650
+ const argExpr = this.evaluateExpression(expr.arguments[i]);
651
+ if (!argExpr.isString() && !argExpr.isNumber()) {
652
+ hasUnknownParams = true;
653
+ break;
654
+ }
655
+
656
+ const value = argExpr.isString()
657
+ ? argExpr.string
658
+ : "" + argExpr.number;
659
+
660
+ const newString = value + (stringSuffix ? stringSuffix.string : "");
661
+ const newRange = [
662
+ argExpr.range[0],
663
+ (stringSuffix || argExpr).range[1]
664
+ ];
665
+ stringSuffix = new BasicEvaluatedExpression()
666
+ .setString(newString)
667
+ .setRange(newRange);
668
+ }
669
+
670
+ if (hasUnknownParams) {
671
+ const prefix = param.isString() ? param : param.prefix;
672
+ return new BasicEvaluatedExpression()
673
+ .setWrapped(prefix, stringSuffix)
674
+ .setRange(expr.range);
675
+ } else if (param.isWrapped()) {
676
+ const postfix = stringSuffix || param.postfix;
677
+ return new BasicEvaluatedExpression()
678
+ .setWrapped(param.prefix, postfix)
679
+ .setRange(expr.range);
680
+ } else {
681
+ const newString =
682
+ param.string + (stringSuffix ? stringSuffix.string : "");
683
+ return new BasicEvaluatedExpression()
684
+ .setString(newString)
685
+ .setRange(expr.range);
686
+ }
687
+ });
688
+ this.hooks.evaluateCallExpressionMember
689
+ .for("split")
690
+ .tap("Parser", (expr, param) => {
691
+ if (!param.isString()) return;
692
+ if (expr.arguments.length !== 1) return;
693
+ let result;
694
+ const arg = this.evaluateExpression(expr.arguments[0]);
695
+ if (arg.isString()) {
696
+ result = param.string.split(arg.string);
697
+ } else if (arg.isRegExp()) {
698
+ result = param.string.split(arg.regExp);
699
+ } else return;
700
+ return new BasicEvaluatedExpression()
701
+ .setArray(result)
702
+ .setRange(expr.range);
703
+ });
704
+ this.hooks.evaluate.for("ConditionalExpression").tap("Parser", expr => {
705
+ const condition = this.evaluateExpression(expr.test);
706
+ const conditionValue = condition.asBool();
707
+ let res;
708
+ if (conditionValue === undefined) {
709
+ const consequent = this.evaluateExpression(expr.consequent);
710
+ const alternate = this.evaluateExpression(expr.alternate);
711
+ if (!consequent || !alternate) return;
712
+ res = new BasicEvaluatedExpression();
713
+ if (consequent.isConditional()) res.setOptions(consequent.options);
714
+ else res.setOptions([consequent]);
715
+ if (alternate.isConditional()) res.addOptions(alternate.options);
716
+ else res.addOptions([alternate]);
717
+ } else {
718
+ res = this.evaluateExpression(
719
+ conditionValue ? expr.consequent : expr.alternate
720
+ );
721
+ }
722
+ res.setRange(expr.range);
723
+ return res;
724
+ });
725
+ this.hooks.evaluate.for("ArrayExpression").tap("Parser", expr => {
726
+ const items = expr.elements.map(element => {
727
+ return element !== null && this.evaluateExpression(element);
728
+ });
729
+ if (!items.every(Boolean)) return;
730
+ return new BasicEvaluatedExpression()
731
+ .setItems(items)
732
+ .setRange(expr.range);
733
+ });
734
+ }
735
+
736
+ getRenameIdentifier(expr) {
737
+ const result = this.evaluateExpression(expr);
738
+ if (!result) return;
739
+ if (result.isIdentifier()) return result.identifier;
740
+ return;
741
+ }
742
+
743
+ walkClass(classy) {
744
+ if (classy.superClass) this.walkExpression(classy.superClass);
745
+ if (classy.body && classy.body.type === "ClassBody") {
746
+ const wasTopLevel = this.scope.topLevelScope;
747
+ this.scope.topLevelScope = false;
748
+ for (const methodDefinition of classy.body.body) {
749
+ if (methodDefinition.type === "MethodDefinition")
750
+ this.walkMethodDefinition(methodDefinition);
751
+ }
752
+ this.scope.topLevelScope = wasTopLevel;
753
+ }
754
+ }
755
+
756
+ walkMethodDefinition(methodDefinition) {
757
+ if (methodDefinition.computed && methodDefinition.key)
758
+ this.walkExpression(methodDefinition.key);
759
+ if (methodDefinition.value) this.walkExpression(methodDefinition.value);
760
+ }
761
+
762
+ // Prewalking iterates the scope for variable declarations
763
+ prewalkStatements(statements) {
764
+ for (let index = 0, len = statements.length; index < len; index++) {
765
+ const statement = statements[index];
766
+ this.prewalkStatement(statement);
767
+ }
768
+ }
769
+
770
+ // Walking iterates the statements and expressions and processes them
771
+ walkStatements(statements) {
772
+ for (let index = 0, len = statements.length; index < len; index++) {
773
+ const statement = statements[index];
774
+ this.walkStatement(statement);
775
+ }
776
+ }
777
+
778
+ prewalkStatement(statement) {
779
+ switch (statement.type) {
780
+ case "BlockStatement":
781
+ this.prewalkBlockStatement(statement);
782
+ break;
783
+ case "ClassDeclaration":
784
+ this.prewalkClassDeclaration(statement);
785
+ break;
786
+ case "DoWhileStatement":
787
+ this.prewalkDoWhileStatement(statement);
788
+ break;
789
+ case "ExportAllDeclaration":
790
+ this.prewalkExportAllDeclaration(statement);
791
+ break;
792
+ case "ExportDefaultDeclaration":
793
+ this.prewalkExportDefaultDeclaration(statement);
794
+ break;
795
+ case "ExportNamedDeclaration":
796
+ this.prewalkExportNamedDeclaration(statement);
797
+ break;
798
+ case "ForInStatement":
799
+ this.prewalkForInStatement(statement);
800
+ break;
801
+ case "ForOfStatement":
802
+ this.prewalkForOfStatement(statement);
803
+ break;
804
+ case "ForStatement":
805
+ this.prewalkForStatement(statement);
806
+ break;
807
+ case "FunctionDeclaration":
808
+ this.prewalkFunctionDeclaration(statement);
809
+ break;
810
+ case "IfStatement":
811
+ this.prewalkIfStatement(statement);
812
+ break;
813
+ case "ImportDeclaration":
814
+ this.prewalkImportDeclaration(statement);
815
+ break;
816
+ case "LabeledStatement":
817
+ this.prewalkLabeledStatement(statement);
818
+ break;
819
+ case "SwitchStatement":
820
+ this.prewalkSwitchStatement(statement);
821
+ break;
822
+ case "TryStatement":
823
+ this.prewalkTryStatement(statement);
824
+ break;
825
+ case "VariableDeclaration":
826
+ this.prewalkVariableDeclaration(statement);
827
+ break;
828
+ case "WhileStatement":
829
+ this.prewalkWhileStatement(statement);
830
+ break;
831
+ case "WithStatement":
832
+ this.prewalkWithStatement(statement);
833
+ break;
834
+ }
835
+ }
836
+
837
+ walkStatement(statement) {
838
+ if (this.hooks.statement.call(statement) !== undefined) return;
839
+ switch (statement.type) {
840
+ case "BlockStatement":
841
+ this.walkBlockStatement(statement);
842
+ break;
843
+ case "ClassDeclaration":
844
+ this.walkClassDeclaration(statement);
845
+ break;
846
+ case "DoWhileStatement":
847
+ this.walkDoWhileStatement(statement);
848
+ break;
849
+ case "ExportDefaultDeclaration":
850
+ this.walkExportDefaultDeclaration(statement);
851
+ break;
852
+ case "ExportNamedDeclaration":
853
+ this.walkExportNamedDeclaration(statement);
854
+ break;
855
+ case "ExpressionStatement":
856
+ this.walkExpressionStatement(statement);
857
+ break;
858
+ case "ForInStatement":
859
+ this.walkForInStatement(statement);
860
+ break;
861
+ case "ForOfStatement":
862
+ this.walkForOfStatement(statement);
863
+ break;
864
+ case "ForStatement":
865
+ this.walkForStatement(statement);
866
+ break;
867
+ case "FunctionDeclaration":
868
+ this.walkFunctionDeclaration(statement);
869
+ break;
870
+ case "IfStatement":
871
+ this.walkIfStatement(statement);
872
+ break;
873
+ case "LabeledStatement":
874
+ this.walkLabeledStatement(statement);
875
+ break;
876
+ case "ReturnStatement":
877
+ this.walkReturnStatement(statement);
878
+ break;
879
+ case "SwitchStatement":
880
+ this.walkSwitchStatement(statement);
881
+ break;
882
+ case "ThrowStatement":
883
+ this.walkThrowStatement(statement);
884
+ break;
885
+ case "TryStatement":
886
+ this.walkTryStatement(statement);
887
+ break;
888
+ case "VariableDeclaration":
889
+ this.walkVariableDeclaration(statement);
890
+ break;
891
+ case "WhileStatement":
892
+ this.walkWhileStatement(statement);
893
+ break;
894
+ case "WithStatement":
895
+ this.walkWithStatement(statement);
896
+ break;
897
+ }
898
+ }
899
+
900
+ // Real Statements
901
+ prewalkBlockStatement(statement) {
902
+ this.prewalkStatements(statement.body);
903
+ }
904
+
905
+ walkBlockStatement(statement) {
906
+ this.walkStatements(statement.body);
907
+ }
908
+
909
+ walkExpressionStatement(statement) {
910
+ this.walkExpression(statement.expression);
911
+ }
912
+
913
+ prewalkIfStatement(statement) {
914
+ this.prewalkStatement(statement.consequent);
915
+ if (statement.alternate) this.prewalkStatement(statement.alternate);
916
+ }
917
+
918
+ walkIfStatement(statement) {
919
+ const result = this.hooks.statementIf.call(statement);
920
+ if (result === undefined) {
921
+ this.walkExpression(statement.test);
922
+ this.walkStatement(statement.consequent);
923
+ if (statement.alternate) this.walkStatement(statement.alternate);
924
+ } else {
925
+ if (result) this.walkStatement(statement.consequent);
926
+ else if (statement.alternate) this.walkStatement(statement.alternate);
927
+ }
928
+ }
929
+
930
+ prewalkLabeledStatement(statement) {
931
+ this.prewalkStatement(statement.body);
932
+ }
933
+
934
+ walkLabeledStatement(statement) {
935
+ const hook = this.hooks.label.get(statement.label.name);
936
+ if (hook !== undefined) {
937
+ const result = hook.call(statement);
938
+ if (result === true) return;
939
+ }
940
+ this.walkStatement(statement.body);
941
+ }
942
+
943
+ prewalkWithStatement(statement) {
944
+ this.prewalkStatement(statement.body);
945
+ }
946
+
947
+ walkWithStatement(statement) {
948
+ this.walkExpression(statement.object);
949
+ this.walkStatement(statement.body);
950
+ }
951
+
952
+ prewalkSwitchStatement(statement) {
953
+ this.prewalkSwitchCases(statement.cases);
954
+ }
955
+
956
+ walkSwitchStatement(statement) {
957
+ this.walkExpression(statement.discriminant);
958
+ this.walkSwitchCases(statement.cases);
959
+ }
960
+
961
+ walkTerminatingStatement(statement) {
962
+ if (statement.argument) this.walkExpression(statement.argument);
963
+ }
964
+
965
+ walkReturnStatement(statement) {
966
+ this.walkTerminatingStatement(statement);
967
+ }
968
+
969
+ walkThrowStatement(statement) {
970
+ this.walkTerminatingStatement(statement);
971
+ }
972
+
973
+ prewalkTryStatement(statement) {
974
+ this.prewalkStatement(statement.block);
975
+ }
976
+
977
+ walkTryStatement(statement) {
978
+ if (this.scope.inTry) {
979
+ this.walkStatement(statement.block);
980
+ } else {
981
+ this.scope.inTry = true;
982
+ this.walkStatement(statement.block);
983
+ this.scope.inTry = false;
984
+ }
985
+ if (statement.handler) this.walkCatchClause(statement.handler);
986
+ if (statement.finalizer) this.walkStatement(statement.finalizer);
987
+ }
988
+
989
+ prewalkWhileStatement(statement) {
990
+ this.prewalkStatement(statement.body);
991
+ }
992
+
993
+ walkWhileStatement(statement) {
994
+ this.walkExpression(statement.test);
995
+ this.walkStatement(statement.body);
996
+ }
997
+
998
+ prewalkDoWhileStatement(statement) {
999
+ this.prewalkStatement(statement.body);
1000
+ }
1001
+
1002
+ walkDoWhileStatement(statement) {
1003
+ this.walkStatement(statement.body);
1004
+ this.walkExpression(statement.test);
1005
+ }
1006
+
1007
+ prewalkForStatement(statement) {
1008
+ if (statement.init) {
1009
+ if (statement.init.type === "VariableDeclaration")
1010
+ this.prewalkStatement(statement.init);
1011
+ }
1012
+ this.prewalkStatement(statement.body);
1013
+ }
1014
+
1015
+ walkForStatement(statement) {
1016
+ if (statement.init) {
1017
+ if (statement.init.type === "VariableDeclaration")
1018
+ this.walkStatement(statement.init);
1019
+ else this.walkExpression(statement.init);
1020
+ }
1021
+ if (statement.test) this.walkExpression(statement.test);
1022
+ if (statement.update) this.walkExpression(statement.update);
1023
+ this.walkStatement(statement.body);
1024
+ }
1025
+
1026
+ prewalkForInStatement(statement) {
1027
+ if (statement.left.type === "VariableDeclaration")
1028
+ this.prewalkVariableDeclaration(statement.left);
1029
+ this.prewalkStatement(statement.body);
1030
+ }
1031
+
1032
+ walkForInStatement(statement) {
1033
+ if (statement.left.type === "VariableDeclaration")
1034
+ this.walkVariableDeclaration(statement.left);
1035
+ else this.walkPattern(statement.left);
1036
+ this.walkExpression(statement.right);
1037
+ this.walkStatement(statement.body);
1038
+ }
1039
+
1040
+ prewalkForOfStatement(statement) {
1041
+ if (statement.left.type === "VariableDeclaration")
1042
+ this.prewalkVariableDeclaration(statement.left);
1043
+ this.prewalkStatement(statement.body);
1044
+ }
1045
+
1046
+ walkForOfStatement(statement) {
1047
+ if (statement.left.type === "VariableDeclaration")
1048
+ this.walkVariableDeclaration(statement.left);
1049
+ else this.walkPattern(statement.left);
1050
+ this.walkExpression(statement.right);
1051
+ this.walkStatement(statement.body);
1052
+ }
1053
+
1054
+ // Declarations
1055
+ prewalkFunctionDeclaration(statement) {
1056
+ if (statement.id) {
1057
+ this.scope.renames.set(statement.id.name, null);
1058
+ this.scope.definitions.add(statement.id.name);
1059
+ }
1060
+ }
1061
+
1062
+ walkFunctionDeclaration(statement) {
1063
+ for (const param of statement.params) this.walkPattern(param);
1064
+ this.inScope(statement.params, () => {
1065
+ this.scope.topLevelScope = false;
1066
+ if (statement.body.type === "BlockStatement") {
1067
+ this.detectStrictMode(statement.body.body);
1068
+ this.prewalkStatement(statement.body);
1069
+ this.walkStatement(statement.body);
1070
+ } else {
1071
+ this.walkExpression(statement.body);
1072
+ }
1073
+ });
1074
+ }
1075
+
1076
+ prewalkImportDeclaration(statement) {
1077
+ const source = statement.source.value;
1078
+ this.hooks.import.call(statement, source);
1079
+ for (const specifier of statement.specifiers) {
1080
+ const name = specifier.local.name;
1081
+ this.scope.renames.set(name, null);
1082
+ this.scope.definitions.add(name);
1083
+ switch (specifier.type) {
1084
+ case "ImportDefaultSpecifier":
1085
+ this.hooks.importSpecifier.call(statement, source, "default", name);
1086
+ break;
1087
+ case "ImportSpecifier":
1088
+ this.hooks.importSpecifier.call(
1089
+ statement,
1090
+ source,
1091
+ specifier.imported.name,
1092
+ name
1093
+ );
1094
+ break;
1095
+ case "ImportNamespaceSpecifier":
1096
+ this.hooks.importSpecifier.call(statement, source, null, name);
1097
+ break;
1098
+ }
1099
+ }
1100
+ }
1101
+
1102
+ prewalkExportNamedDeclaration(statement) {
1103
+ let source;
1104
+ if (statement.source) {
1105
+ source = statement.source.value;
1106
+ this.hooks.exportImport.call(statement, source);
1107
+ } else {
1108
+ this.hooks.export.call(statement);
1109
+ }
1110
+ if (statement.declaration) {
1111
+ if (
1112
+ !this.hooks.exportDeclaration.call(statement, statement.declaration)
1113
+ ) {
1114
+ const originalDefinitions = this.scope.definitions;
1115
+ const tracker = new TrackingSet(this.scope.definitions);
1116
+ this.scope.definitions = tracker;
1117
+ this.prewalkStatement(statement.declaration);
1118
+ const newDefs = Array.from(tracker.getAddedItems());
1119
+ this.scope.definitions = originalDefinitions;
1120
+ for (let index = newDefs.length - 1; index >= 0; index--) {
1121
+ const def = newDefs[index];
1122
+ this.hooks.exportSpecifier.call(statement, def, def, index);
1123
+ }
1124
+ }
1125
+ }
1126
+ if (statement.specifiers) {
1127
+ for (
1128
+ let specifierIndex = 0;
1129
+ specifierIndex < statement.specifiers.length;
1130
+ specifierIndex++
1131
+ ) {
1132
+ const specifier = statement.specifiers[specifierIndex];
1133
+ switch (specifier.type) {
1134
+ case "ExportSpecifier": {
1135
+ const name = specifier.exported.name;
1136
+ if (source)
1137
+ this.hooks.exportImportSpecifier.call(
1138
+ statement,
1139
+ source,
1140
+ specifier.local.name,
1141
+ name,
1142
+ specifierIndex
1143
+ );
1144
+ else
1145
+ this.hooks.exportSpecifier.call(
1146
+ statement,
1147
+ specifier.local.name,
1148
+ name,
1149
+ specifierIndex
1150
+ );
1151
+ break;
1152
+ }
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ walkExportNamedDeclaration(statement) {
1159
+ if (statement.declaration) {
1160
+ this.walkStatement(statement.declaration);
1161
+ }
1162
+ }
1163
+
1164
+ prewalkExportDefaultDeclaration(statement) {
1165
+ if (statement.declaration.id) {
1166
+ const originalDefinitions = this.scope.definitions;
1167
+ const tracker = new TrackingSet(this.scope.definitions);
1168
+ this.scope.definitions = tracker;
1169
+ this.prewalkStatement(statement.declaration);
1170
+ const newDefs = Array.from(tracker.getAddedItems());
1171
+ this.scope.definitions = originalDefinitions;
1172
+ for (let index = 0, len = newDefs.length; index < len; index++) {
1173
+ const def = newDefs[index];
1174
+ this.hooks.exportSpecifier.call(statement, def, "default");
1175
+ }
1176
+ }
1177
+ }
1178
+
1179
+ walkExportDefaultDeclaration(statement) {
1180
+ this.hooks.export.call(statement);
1181
+ if (
1182
+ statement.declaration.id &&
1183
+ statement.declaration.type !== "FunctionExpression" &&
1184
+ statement.declaration.type !== "ClassExpression"
1185
+ ) {
1186
+ if (
1187
+ !this.hooks.exportDeclaration.call(statement, statement.declaration)
1188
+ ) {
1189
+ this.walkStatement(statement.declaration);
1190
+ }
1191
+ } else {
1192
+ // Acorn parses `export default function() {}` as `FunctionDeclaration` and
1193
+ // `export default class {}` as `ClassDeclaration`, both with `id = null`.
1194
+ // These nodes must be treated as expressions.
1195
+ if (statement.declaration.type === "FunctionDeclaration") {
1196
+ this.walkFunctionDeclaration(statement.declaration);
1197
+ } else if (statement.declaration.type === "ClassDeclaration") {
1198
+ this.walkClassDeclaration(statement.declaration);
1199
+ } else {
1200
+ this.walkExpression(statement.declaration);
1201
+ }
1202
+ if (!this.hooks.exportExpression.call(statement, statement.declaration)) {
1203
+ this.hooks.exportSpecifier.call(
1204
+ statement,
1205
+ statement.declaration,
1206
+ "default"
1207
+ );
1208
+ }
1209
+ }
1210
+ }
1211
+
1212
+ prewalkExportAllDeclaration(statement) {
1213
+ const source = statement.source.value;
1214
+ this.hooks.exportImport.call(statement, source);
1215
+ this.hooks.exportImportSpecifier.call(statement, source, null, null, 0);
1216
+ }
1217
+
1218
+ prewalkVariableDeclaration(statement) {
1219
+ const hookMap =
1220
+ statement.kind === "const"
1221
+ ? this.hooks.varDeclarationConst
1222
+ : statement.kind === "let"
1223
+ ? this.hooks.varDeclarationLet
1224
+ : this.hooks.varDeclarationVar;
1225
+ for (const declarator of statement.declarations) {
1226
+ switch (declarator.type) {
1227
+ case "VariableDeclarator": {
1228
+ this.enterPattern(declarator.id, (name, decl) => {
1229
+ let hook = hookMap.get(name);
1230
+ if (hook === undefined || !hook.call(decl)) {
1231
+ hook = this.hooks.varDeclaration.get(name);
1232
+ if (hook === undefined || !hook.call(decl)) {
1233
+ this.scope.renames.set(name, null);
1234
+ this.scope.definitions.add(name);
1235
+ }
1236
+ }
1237
+ });
1238
+ break;
1239
+ }
1240
+ }
1241
+ }
1242
+ }
1243
+
1244
+ walkVariableDeclaration(statement) {
1245
+ for (const declarator of statement.declarations) {
1246
+ switch (declarator.type) {
1247
+ case "VariableDeclarator": {
1248
+ const renameIdentifier =
1249
+ declarator.init && this.getRenameIdentifier(declarator.init);
1250
+ if (renameIdentifier && declarator.id.type === "Identifier") {
1251
+ const hook = this.hooks.canRename.get(renameIdentifier);
1252
+ if (hook !== undefined && hook.call(declarator.init)) {
1253
+ // renaming with "var a = b;"
1254
+ const hook = this.hooks.rename.get(renameIdentifier);
1255
+ if (hook === undefined || !hook.call(declarator.init)) {
1256
+ this.scope.renames.set(
1257
+ declarator.id.name,
1258
+ this.scope.renames.get(renameIdentifier) || renameIdentifier
1259
+ );
1260
+ this.scope.definitions.delete(declarator.id.name);
1261
+ }
1262
+ break;
1263
+ }
1264
+ }
1265
+ this.walkPattern(declarator.id);
1266
+ if (declarator.init) this.walkExpression(declarator.init);
1267
+ break;
1268
+ }
1269
+ }
1270
+ }
1271
+ }
1272
+
1273
+ prewalkClassDeclaration(statement) {
1274
+ if (statement.id) {
1275
+ this.scope.renames.set(statement.id.name, null);
1276
+ this.scope.definitions.add(statement.id.name);
1277
+ }
1278
+ }
1279
+
1280
+ walkClassDeclaration(statement) {
1281
+ this.walkClass(statement);
1282
+ }
1283
+
1284
+ prewalkSwitchCases(switchCases) {
1285
+ for (let index = 0, len = switchCases.length; index < len; index++) {
1286
+ const switchCase = switchCases[index];
1287
+ this.prewalkStatements(switchCase.consequent);
1288
+ }
1289
+ }
1290
+
1291
+ walkSwitchCases(switchCases) {
1292
+ for (let index = 0, len = switchCases.length; index < len; index++) {
1293
+ const switchCase = switchCases[index];
1294
+
1295
+ if (switchCase.test) {
1296
+ this.walkExpression(switchCase.test);
1297
+ }
1298
+ this.walkStatements(switchCase.consequent);
1299
+ }
1300
+ }
1301
+
1302
+ walkCatchClause(catchClause) {
1303
+ this.inScope([catchClause.param], () => {
1304
+ this.prewalkStatement(catchClause.body);
1305
+ this.walkStatement(catchClause.body);
1306
+ });
1307
+ }
1308
+
1309
+ walkPattern(pattern) {
1310
+ switch (pattern.type) {
1311
+ case "ArrayPattern":
1312
+ this.walkArrayPattern(pattern);
1313
+ break;
1314
+ case "AssignmentPattern":
1315
+ this.walkAssignmentPattern(pattern);
1316
+ break;
1317
+ case "MemberExpression":
1318
+ this.walkMemberExpression(pattern);
1319
+ break;
1320
+ case "ObjectPattern":
1321
+ this.walkObjectPattern(pattern);
1322
+ break;
1323
+ case "RestElement":
1324
+ this.walkRestElement(pattern);
1325
+ break;
1326
+ }
1327
+ }
1328
+
1329
+ walkAssignmentPattern(pattern) {
1330
+ this.walkExpression(pattern.right);
1331
+ this.walkPattern(pattern.left);
1332
+ }
1333
+
1334
+ walkObjectPattern(pattern) {
1335
+ for (let i = 0, len = pattern.properties.length; i < len; i++) {
1336
+ const prop = pattern.properties[i];
1337
+ if (prop) {
1338
+ if (prop.computed) this.walkExpression(prop.key);
1339
+ if (prop.value) this.walkPattern(prop.value);
1340
+ }
1341
+ }
1342
+ }
1343
+
1344
+ walkArrayPattern(pattern) {
1345
+ for (let i = 0, len = pattern.elements.length; i < len; i++) {
1346
+ const element = pattern.elements[i];
1347
+ if (element) this.walkPattern(element);
1348
+ }
1349
+ }
1350
+
1351
+ walkRestElement(pattern) {
1352
+ this.walkPattern(pattern.argument);
1353
+ }
1354
+
1355
+ walkExpressions(expressions) {
1356
+ for (
1357
+ let expressionsIndex = 0, len = expressions.length;
1358
+ expressionsIndex < len;
1359
+ expressionsIndex++
1360
+ ) {
1361
+ const expression = expressions[expressionsIndex];
1362
+ if (expression) this.walkExpression(expression);
1363
+ }
1364
+ }
1365
+
1366
+ walkExpression(expression) {
1367
+ switch (expression.type) {
1368
+ case "ArrayExpression":
1369
+ this.walkArrayExpression(expression);
1370
+ break;
1371
+ case "ArrowFunctionExpression":
1372
+ this.walkArrowFunctionExpression(expression);
1373
+ break;
1374
+ case "AssignmentExpression":
1375
+ this.walkAssignmentExpression(expression);
1376
+ break;
1377
+ case "AwaitExpression":
1378
+ this.walkAwaitExpression(expression);
1379
+ break;
1380
+ case "BinaryExpression":
1381
+ this.walkBinaryExpression(expression);
1382
+ break;
1383
+ case "CallExpression":
1384
+ this.walkCallExpression(expression);
1385
+ break;
1386
+ case "ClassExpression":
1387
+ this.walkClassExpression(expression);
1388
+ break;
1389
+ case "ConditionalExpression":
1390
+ this.walkConditionalExpression(expression);
1391
+ break;
1392
+ case "FunctionExpression":
1393
+ this.walkFunctionExpression(expression);
1394
+ break;
1395
+ case "Identifier":
1396
+ this.walkIdentifier(expression);
1397
+ break;
1398
+ case "LogicalExpression":
1399
+ this.walkLogicalExpression(expression);
1400
+ break;
1401
+ case "MemberExpression":
1402
+ this.walkMemberExpression(expression);
1403
+ break;
1404
+ case "NewExpression":
1405
+ this.walkNewExpression(expression);
1406
+ break;
1407
+ case "ObjectExpression":
1408
+ this.walkObjectExpression(expression);
1409
+ break;
1410
+ case "SequenceExpression":
1411
+ this.walkSequenceExpression(expression);
1412
+ break;
1413
+ case "SpreadElement":
1414
+ this.walkSpreadElement(expression);
1415
+ break;
1416
+ case "TaggedTemplateExpression":
1417
+ this.walkTaggedTemplateExpression(expression);
1418
+ break;
1419
+ case "TemplateLiteral":
1420
+ this.walkTemplateLiteral(expression);
1421
+ break;
1422
+ case "ThisExpression":
1423
+ this.walkThisExpression(expression);
1424
+ break;
1425
+ case "UnaryExpression":
1426
+ this.walkUnaryExpression(expression);
1427
+ break;
1428
+ case "UpdateExpression":
1429
+ this.walkUpdateExpression(expression);
1430
+ break;
1431
+ case "YieldExpression":
1432
+ this.walkYieldExpression(expression);
1433
+ break;
1434
+ }
1435
+ }
1436
+
1437
+ walkAwaitExpression(expression) {
1438
+ this.walkExpression(expression.argument);
1439
+ }
1440
+
1441
+ walkArrayExpression(expression) {
1442
+ if (expression.elements) this.walkExpressions(expression.elements);
1443
+ }
1444
+
1445
+ walkSpreadElement(expression) {
1446
+ if (expression.argument) this.walkExpression(expression.argument);
1447
+ }
1448
+
1449
+ walkObjectExpression(expression) {
1450
+ for (
1451
+ let propIndex = 0, len = expression.properties.length;
1452
+ propIndex < len;
1453
+ propIndex++
1454
+ ) {
1455
+ const prop = expression.properties[propIndex];
1456
+ if (prop.type === "SpreadElement") {
1457
+ this.walkExpression(prop.argument);
1458
+ continue;
1459
+ }
1460
+ if (prop.computed) this.walkExpression(prop.key);
1461
+ if (prop.shorthand) this.scope.inShorthand = true;
1462
+ this.walkExpression(prop.value);
1463
+ if (prop.shorthand) this.scope.inShorthand = false;
1464
+ }
1465
+ }
1466
+
1467
+ walkFunctionExpression(expression) {
1468
+ for (const param of expression.params) this.walkPattern(param);
1469
+ this.inScope(expression.params, () => {
1470
+ this.scope.topLevelScope = false;
1471
+ if (expression.body.type === "BlockStatement") {
1472
+ this.detectStrictMode(expression.body.body);
1473
+ this.prewalkStatement(expression.body);
1474
+ this.walkStatement(expression.body);
1475
+ } else {
1476
+ this.walkExpression(expression.body);
1477
+ }
1478
+ });
1479
+ }
1480
+
1481
+ walkArrowFunctionExpression(expression) {
1482
+ for (const param of expression.params) this.walkPattern(param);
1483
+ this.inScope(expression.params, () => {
1484
+ if (expression.body.type === "BlockStatement") {
1485
+ this.detectStrictMode(expression.body.body);
1486
+ this.prewalkStatement(expression.body);
1487
+ this.walkStatement(expression.body);
1488
+ } else {
1489
+ this.walkExpression(expression.body);
1490
+ }
1491
+ });
1492
+ }
1493
+
1494
+ walkSequenceExpression(expression) {
1495
+ if (expression.expressions) this.walkExpressions(expression.expressions);
1496
+ }
1497
+
1498
+ walkUpdateExpression(expression) {
1499
+ this.walkExpression(expression.argument);
1500
+ }
1501
+
1502
+ walkUnaryExpression(expression) {
1503
+ if (expression.operator === "typeof") {
1504
+ const exprName = this.getNameForExpression(expression.argument);
1505
+ if (exprName && exprName.free) {
1506
+ const hook = this.hooks.typeof.get(exprName.name);
1507
+ if (hook !== undefined) {
1508
+ const result = hook.call(expression);
1509
+ if (result === true) return;
1510
+ }
1511
+ }
1512
+ }
1513
+ this.walkExpression(expression.argument);
1514
+ }
1515
+
1516
+ walkLeftRightExpression(expression) {
1517
+ this.walkExpression(expression.left);
1518
+ this.walkExpression(expression.right);
1519
+ }
1520
+
1521
+ walkBinaryExpression(expression) {
1522
+ this.walkLeftRightExpression(expression);
1523
+ }
1524
+
1525
+ walkLogicalExpression(expression) {
1526
+ this.walkLeftRightExpression(expression);
1527
+ }
1528
+
1529
+ walkAssignmentExpression(expression) {
1530
+ const renameIdentifier = this.getRenameIdentifier(expression.right);
1531
+ if (expression.left.type === "Identifier" && renameIdentifier) {
1532
+ const hook = this.hooks.canRename.get(renameIdentifier);
1533
+ if (hook !== undefined && hook.call(expression.right)) {
1534
+ // renaming "a = b;"
1535
+ const hook = this.hooks.rename.get(renameIdentifier);
1536
+ if (hook === undefined || !hook.call(expression.right)) {
1537
+ this.scope.renames.set(expression.left.name, renameIdentifier);
1538
+ this.scope.definitions.delete(expression.left.name);
1539
+ }
1540
+ return;
1541
+ }
1542
+ }
1543
+ if (expression.left.type === "Identifier") {
1544
+ const assignedHook = this.hooks.assigned.get(expression.left.name);
1545
+ if (assignedHook === undefined || !assignedHook.call(expression)) {
1546
+ this.walkExpression(expression.right);
1547
+ }
1548
+ this.scope.renames.set(expression.left.name, null);
1549
+ const assignHook = this.hooks.assign.get(expression.left.name);
1550
+ if (assignHook === undefined || !assignHook.call(expression)) {
1551
+ this.walkExpression(expression.left);
1552
+ }
1553
+ return;
1554
+ }
1555
+ this.walkExpression(expression.right);
1556
+ this.walkPattern(expression.left);
1557
+ this.enterPattern(expression.left, (name, decl) => {
1558
+ this.scope.renames.set(name, null);
1559
+ });
1560
+ }
1561
+
1562
+ walkConditionalExpression(expression) {
1563
+ const result = this.hooks.expressionConditionalOperator.call(expression);
1564
+ if (result === undefined) {
1565
+ this.walkExpression(expression.test);
1566
+ this.walkExpression(expression.consequent);
1567
+ if (expression.alternate) this.walkExpression(expression.alternate);
1568
+ } else {
1569
+ if (result) this.walkExpression(expression.consequent);
1570
+ else if (expression.alternate) this.walkExpression(expression.alternate);
1571
+ }
1572
+ }
1573
+
1574
+ walkNewExpression(expression) {
1575
+ const callee = this.evaluateExpression(expression.callee);
1576
+ if (callee.isIdentifier()) {
1577
+ const hook = this.hooks.new.get(callee.identifier);
1578
+ if (hook !== undefined) {
1579
+ const result = hook.call(expression);
1580
+ if (result === true) {
1581
+ return;
1582
+ }
1583
+ }
1584
+ }
1585
+
1586
+ this.walkExpression(expression.callee);
1587
+ if (expression.arguments) this.walkExpressions(expression.arguments);
1588
+ }
1589
+
1590
+ walkYieldExpression(expression) {
1591
+ if (expression.argument) this.walkExpression(expression.argument);
1592
+ }
1593
+
1594
+ walkTemplateLiteral(expression) {
1595
+ if (expression.expressions) this.walkExpressions(expression.expressions);
1596
+ }
1597
+
1598
+ walkTaggedTemplateExpression(expression) {
1599
+ if (expression.tag) this.walkExpression(expression.tag);
1600
+ if (expression.quasi && expression.quasi.expressions)
1601
+ this.walkExpressions(expression.quasi.expressions);
1602
+ }
1603
+
1604
+ walkClassExpression(expression) {
1605
+ this.walkClass(expression);
1606
+ }
1607
+
1608
+ walkCallExpression(expression) {
1609
+ let result;
1610
+
1611
+ const walkIIFE = (functionExpression, options, currentThis) => {
1612
+ const renameArgOrThis = argOrThis => {
1613
+ const renameIdentifier = this.getRenameIdentifier(argOrThis);
1614
+ if (renameIdentifier) {
1615
+ const hook = this.hooks.canRename.get(renameIdentifier);
1616
+ if (hook !== undefined && hook.call(argOrThis)) {
1617
+ const hook = this.hooks.rename.get(renameIdentifier);
1618
+ if (hook === undefined || !hook.call(argOrThis))
1619
+ return renameIdentifier;
1620
+ }
1621
+ }
1622
+ this.walkExpression(argOrThis);
1623
+ };
1624
+ const params = functionExpression.params;
1625
+ const renameThis = currentThis
1626
+ ? renameArgOrThis.call(this, currentThis)
1627
+ : null;
1628
+ const args = options.map(renameArgOrThis);
1629
+ this.inScope(params.filter((identifier, idx) => !args[idx]), () => {
1630
+ if (renameThis) {
1631
+ this.scope.renames.set("this", renameThis);
1632
+ }
1633
+ for (let i = 0; i < args.length; i++) {
1634
+ const param = args[i];
1635
+ if (!param) continue;
1636
+ if (!params[i] || params[i].type !== "Identifier") continue;
1637
+ this.scope.renames.set(params[i].name, param);
1638
+ }
1639
+ if (functionExpression.body.type === "BlockStatement") {
1640
+ this.prewalkStatement(functionExpression.body);
1641
+ this.walkStatement(functionExpression.body);
1642
+ } else this.walkExpression(functionExpression.body);
1643
+ });
1644
+ };
1645
+ if (
1646
+ expression.callee.type === "MemberExpression" &&
1647
+ expression.callee.object.type === "FunctionExpression" &&
1648
+ !expression.callee.computed &&
1649
+ (expression.callee.property.name === "call" ||
1650
+ expression.callee.property.name === "bind") &&
1651
+ expression.arguments &&
1652
+ expression.arguments.length > 0
1653
+ ) {
1654
+ // (function(…) { }.call/bind(?, …))
1655
+ walkIIFE.call(
1656
+ this,
1657
+ expression.callee.object,
1658
+ expression.arguments.slice(1),
1659
+ expression.arguments[0]
1660
+ );
1661
+ } else if (
1662
+ expression.callee.type === "FunctionExpression" &&
1663
+ expression.arguments
1664
+ ) {
1665
+ // (function(…) { }())
1666
+ walkIIFE.call(this, expression.callee, expression.arguments);
1667
+ } else if (expression.callee.type === "Import") {
1668
+ result = this.hooks.importCall.call(expression);
1669
+ if (result === true) return;
1670
+
1671
+ if (expression.arguments) this.walkExpressions(expression.arguments);
1672
+ } else {
1673
+ const callee = this.evaluateExpression(expression.callee);
1674
+ if (callee.isIdentifier()) {
1675
+ const callHook = this.hooks.call.get(callee.identifier);
1676
+ if (callHook !== undefined) {
1677
+ result = callHook.call(expression);
1678
+ if (result === true) return;
1679
+ }
1680
+ let identifier = callee.identifier.replace(/\.[^.]+$/, "");
1681
+ if (identifier !== callee.identifier) {
1682
+ const callAnyHook = this.hooks.callAnyMember.get(identifier);
1683
+ if (callAnyHook !== undefined) {
1684
+ result = callAnyHook.call(expression);
1685
+ if (result === true) return;
1686
+ }
1687
+ }
1688
+ }
1689
+
1690
+ if (expression.callee) this.walkExpression(expression.callee);
1691
+ if (expression.arguments) this.walkExpressions(expression.arguments);
1692
+ }
1693
+ }
1694
+
1695
+ walkMemberExpression(expression) {
1696
+ const exprName = this.getNameForExpression(expression);
1697
+ if (exprName && exprName.free) {
1698
+ const expressionHook = this.hooks.expression.get(exprName.name);
1699
+ if (expressionHook !== undefined) {
1700
+ const result = expressionHook.call(expression);
1701
+ if (result === true) return;
1702
+ }
1703
+ const expressionAnyMemberHook = this.hooks.expressionAnyMember.get(
1704
+ exprName.nameGeneral
1705
+ );
1706
+ if (expressionAnyMemberHook !== undefined) {
1707
+ const result = expressionAnyMemberHook.call(expression);
1708
+ if (result === true) return;
1709
+ }
1710
+ }
1711
+ this.walkExpression(expression.object);
1712
+ if (expression.computed === true) this.walkExpression(expression.property);
1713
+ }
1714
+
1715
+ walkThisExpression(expression) {
1716
+ const expressionHook = this.hooks.expression.get("this");
1717
+ if (expressionHook !== undefined) {
1718
+ expressionHook.call(expression);
1719
+ }
1720
+ }
1721
+
1722
+ walkIdentifier(expression) {
1723
+ if (!this.scope.definitions.has(expression.name)) {
1724
+ const hook = this.hooks.expression.get(
1725
+ this.scope.renames.get(expression.name) || expression.name
1726
+ );
1727
+ if (hook !== undefined) {
1728
+ const result = hook.call(expression);
1729
+ if (result === true) return;
1730
+ }
1731
+ }
1732
+ }
1733
+
1734
+ inScope(params, fn) {
1735
+ const oldScope = this.scope;
1736
+ this.scope = {
1737
+ topLevelScope: oldScope.topLevelScope,
1738
+ inTry: false,
1739
+ inShorthand: false,
1740
+ isStrict: oldScope.isStrict,
1741
+ definitions: oldScope.definitions.createChild(),
1742
+ renames: oldScope.renames.createChild()
1743
+ };
1744
+
1745
+ this.scope.renames.set("this", null);
1746
+
1747
+ for (
1748
+ let paramIndex = 0, len = params.length;
1749
+ paramIndex < len;
1750
+ paramIndex++
1751
+ ) {
1752
+ const param = params[paramIndex];
1753
+
1754
+ if (typeof param !== "string") {
1755
+ this.enterPattern(param, param => {
1756
+ this.scope.renames.set(param, null);
1757
+ this.scope.definitions.add(param);
1758
+ });
1759
+ } else if (param) {
1760
+ this.scope.renames.set(param, null);
1761
+ this.scope.definitions.add(param);
1762
+ }
1763
+ }
1764
+
1765
+ fn();
1766
+ this.scope = oldScope;
1767
+ }
1768
+
1769
+ detectStrictMode(statements) {
1770
+ const isStrict =
1771
+ statements.length >= 1 &&
1772
+ statements[0].type === "ExpressionStatement" &&
1773
+ statements[0].expression.type === "Literal" &&
1774
+ statements[0].expression.value === "use strict";
1775
+ if (isStrict) {
1776
+ this.scope.isStrict = true;
1777
+ }
1778
+ }
1779
+
1780
+ enterPattern(pattern, onIdent) {
1781
+ if (!pattern) return;
1782
+ switch (pattern.type) {
1783
+ case "ArrayPattern":
1784
+ this.enterArrayPattern(pattern, onIdent);
1785
+ break;
1786
+ case "AssignmentPattern":
1787
+ this.enterAssignmentPattern(pattern, onIdent);
1788
+ break;
1789
+ case "Identifier":
1790
+ this.enterIdentifier(pattern, onIdent);
1791
+ break;
1792
+ case "ObjectPattern":
1793
+ this.enterObjectPattern(pattern, onIdent);
1794
+ break;
1795
+ case "RestElement":
1796
+ this.enterRestElement(pattern, onIdent);
1797
+ break;
1798
+ }
1799
+ }
1800
+
1801
+ enterIdentifier(pattern, onIdent) {
1802
+ onIdent(pattern.name, pattern);
1803
+ }
1804
+
1805
+ enterObjectPattern(pattern, onIdent) {
1806
+ for (
1807
+ let propIndex = 0, len = pattern.properties.length;
1808
+ propIndex < len;
1809
+ propIndex++
1810
+ ) {
1811
+ const prop = pattern.properties[propIndex];
1812
+ this.enterPattern(prop.value, onIdent);
1813
+ }
1814
+ }
1815
+
1816
+ enterArrayPattern(pattern, onIdent) {
1817
+ for (
1818
+ let elementIndex = 0, len = pattern.elements.length;
1819
+ elementIndex < len;
1820
+ elementIndex++
1821
+ ) {
1822
+ const element = pattern.elements[elementIndex];
1823
+ this.enterPattern(element, onIdent);
1824
+ }
1825
+ }
1826
+
1827
+ enterRestElement(pattern, onIdent) {
1828
+ this.enterPattern(pattern.argument, onIdent);
1829
+ }
1830
+
1831
+ enterAssignmentPattern(pattern, onIdent) {
1832
+ this.enterPattern(pattern.left, onIdent);
1833
+ }
1834
+
1835
+ evaluateExpression(expression) {
1836
+ try {
1837
+ const hook = this.hooks.evaluate.get(expression.type);
1838
+ if (hook !== undefined) {
1839
+ const result = hook.call(expression);
1840
+ if (result !== undefined) return result;
1841
+ }
1842
+ } catch (e) {
1843
+ console.warn(e);
1844
+ // ignore error
1845
+ }
1846
+ return new BasicEvaluatedExpression().setRange(expression.range);
1847
+ }
1848
+
1849
+ parseString(expression) {
1850
+ switch (expression.type) {
1851
+ case "BinaryExpression":
1852
+ if (expression.operator === "+")
1853
+ return (
1854
+ this.parseString(expression.left) +
1855
+ this.parseString(expression.right)
1856
+ );
1857
+ break;
1858
+ case "Literal":
1859
+ return expression.value + "";
1860
+ }
1861
+ throw new Error(
1862
+ expression.type + " is not supported as parameter for require"
1863
+ );
1864
+ }
1865
+
1866
+ parseCalculatedString(expression) {
1867
+ switch (expression.type) {
1868
+ case "BinaryExpression":
1869
+ if (expression.operator === "+") {
1870
+ const left = this.parseCalculatedString(expression.left);
1871
+ const right = this.parseCalculatedString(expression.right);
1872
+ if (left.code) {
1873
+ return {
1874
+ range: left.range,
1875
+ value: left.value,
1876
+ code: true
1877
+ };
1878
+ } else if (right.code) {
1879
+ return {
1880
+ range: [
1881
+ left.range[0],
1882
+ right.range ? right.range[1] : left.range[1]
1883
+ ],
1884
+ value: left.value + right.value,
1885
+ code: true
1886
+ };
1887
+ } else {
1888
+ return {
1889
+ range: [left.range[0], right.range[1]],
1890
+ value: left.value + right.value
1891
+ };
1892
+ }
1893
+ }
1894
+ break;
1895
+ case "ConditionalExpression": {
1896
+ const consequent = this.parseCalculatedString(expression.consequent);
1897
+ const alternate = this.parseCalculatedString(expression.alternate);
1898
+ const items = [];
1899
+ if (consequent.conditional) items.push(...consequent.conditional);
1900
+ else if (!consequent.code) items.push(consequent);
1901
+ else break;
1902
+ if (alternate.conditional) items.push(...alternate.conditional);
1903
+ else if (!alternate.code) items.push(alternate);
1904
+ else break;
1905
+ return {
1906
+ value: "",
1907
+ code: true,
1908
+ conditional: items
1909
+ };
1910
+ }
1911
+ case "Literal":
1912
+ return {
1913
+ range: expression.range,
1914
+ value: expression.value + ""
1915
+ };
1916
+ }
1917
+ return {
1918
+ value: "",
1919
+ code: true
1920
+ };
1921
+ }
1922
+
1923
+ parse(source, initialState) {
1924
+ let ast;
1925
+ let comments;
1926
+ if (typeof source === "object" && source !== null) {
1927
+ ast = source;
1928
+ comments = source.comments;
1929
+ } else {
1930
+ comments = [];
1931
+ ast = Parser.parse(source, {
1932
+ sourceType: this.sourceType,
1933
+ onComment: comments
1934
+ });
1935
+ }
1936
+
1937
+ const oldScope = this.scope;
1938
+ const oldState = this.state;
1939
+ const oldComments = this.comments;
1940
+ this.scope = {
1941
+ topLevelScope: true,
1942
+ inTry: false,
1943
+ inShorthand: false,
1944
+ isStrict: false,
1945
+ definitions: new StackedSetMap(),
1946
+ renames: new StackedSetMap()
1947
+ };
1948
+ const state = (this.state = initialState || {});
1949
+ this.comments = comments;
1950
+ if (this.hooks.program.call(ast, comments) === undefined) {
1951
+ this.detectStrictMode(ast.body);
1952
+ this.prewalkStatements(ast.body);
1953
+ this.walkStatements(ast.body);
1954
+ }
1955
+ this.scope = oldScope;
1956
+ this.state = oldState;
1957
+ this.comments = oldComments;
1958
+ return state;
1959
+ }
1960
+
1961
+ evaluate(source) {
1962
+ const ast = Parser.parse("(" + source + ")", {
1963
+ sourceType: this.sourceType,
1964
+ locations: false
1965
+ });
1966
+ if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement")
1967
+ throw new Error("evaluate: Source is not a expression");
1968
+ return this.evaluateExpression(ast.body[0].expression);
1969
+ }
1970
+
1971
+ getComments(range) {
1972
+ return this.comments.filter(
1973
+ comment => comment.range[0] >= range[0] && comment.range[1] <= range[1]
1974
+ );
1975
+ }
1976
+
1977
+ getCommentOptions(range) {
1978
+ const comments = this.getComments(range);
1979
+ if (comments.length === 0) return null;
1980
+ const options = comments.map(comment => {
1981
+ try {
1982
+ let val = vm.runInNewContext(
1983
+ `(function(){return {${comment.value}};})()`
1984
+ );
1985
+ return val;
1986
+ } catch (e) {
1987
+ return {};
1988
+ }
1989
+ });
1990
+ return options.reduce((o, i) => Object.assign(o, i), {});
1991
+ }
1992
+
1993
+ getNameForExpression(expression) {
1994
+ let expr = expression;
1995
+ const exprName = [];
1996
+ while (
1997
+ expr.type === "MemberExpression" &&
1998
+ expr.property.type === (expr.computed ? "Literal" : "Identifier")
1999
+ ) {
2000
+ exprName.push(expr.computed ? expr.property.value : expr.property.name);
2001
+ expr = expr.object;
2002
+ }
2003
+ let free;
2004
+ if (expr.type === "Identifier") {
2005
+ free = !this.scope.definitions.has(expr.name);
2006
+ exprName.push(this.scope.renames.get(expr.name) || expr.name);
2007
+ } else if (
2008
+ expr.type === "ThisExpression" &&
2009
+ this.scope.renames.get("this")
2010
+ ) {
2011
+ free = true;
2012
+ exprName.push(this.scope.renames.get("this"));
2013
+ } else if (expr.type === "ThisExpression") {
2014
+ free = this.scope.topLevelScope;
2015
+ exprName.push("this");
2016
+ } else {
2017
+ return null;
2018
+ }
2019
+ let prefix = "";
2020
+ for (let i = exprName.length - 1; i >= 2; i--) prefix += exprName[i] + ".";
2021
+ if (exprName.length > 1) prefix += exprName[1];
2022
+ const name = prefix ? prefix + "." + exprName[0] : exprName[0];
2023
+ const nameGeneral = prefix;
2024
+ return {
2025
+ name,
2026
+ nameGeneral,
2027
+ free
2028
+ };
2029
+ }
2030
+
2031
+ static parse(code, options) {
2032
+ const type = options ? options.sourceType : "module";
2033
+ const parserOptions = Object.assign(
2034
+ Object.create(null),
2035
+ defaultParserOptions,
2036
+ options
2037
+ );
2038
+
2039
+ if (type === "auto") {
2040
+ parserOptions.sourceType = "module";
2041
+ }
2042
+
2043
+ let ast;
2044
+ let error;
2045
+ let threw = false;
2046
+ try {
2047
+ ast = acorn.parse(code, parserOptions);
2048
+ } catch (e) {
2049
+ error = e;
2050
+ threw = true;
2051
+ }
2052
+
2053
+ if (threw && type === "auto") {
2054
+ parserOptions.sourceType = "script";
2055
+ if (Array.isArray(parserOptions.onComment)) {
2056
+ parserOptions.onComment.length = 0;
2057
+ }
2058
+ try {
2059
+ ast = acorn.parse(code, parserOptions);
2060
+ threw = false;
2061
+ } catch (e) {
2062
+ threw = true;
2063
+ }
2064
+ }
2065
+
2066
+ if (threw) {
2067
+ throw error;
2068
+ }
2069
+
2070
+ return ast;
2071
+ }
2072
+ }
2073
+
2074
+ module.exports = Parser;