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