webpack 4.9.1 → 4.10.2

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