webpack 1.13.3 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +310 -310
  3. package/buildin/amd-define.js +1 -1
  4. package/buildin/amd-options.js +1 -1
  5. package/buildin/module.js +10 -10
  6. package/hot/dev-server.js +63 -63
  7. package/hot/log-apply-result.js +25 -25
  8. package/hot/only-dev-server.js +77 -77
  9. package/hot/poll.js +37 -37
  10. package/hot/signal.js +65 -65
  11. package/lib/APIPlugin.js +49 -49
  12. package/lib/AbstractPlugin.js +22 -22
  13. package/lib/AmdMainTemplatePlugin.js +43 -43
  14. package/lib/ArrayMap.js +50 -50
  15. package/lib/AsyncDependenciesBlock.js +39 -39
  16. package/lib/AutomaticPrefetchPlugin.js +35 -35
  17. package/lib/BannerPlugin.js +34 -34
  18. package/lib/BasicEvaluatedExpression.js +140 -140
  19. package/lib/CachePlugin.js +43 -43
  20. package/lib/CaseSensitiveModulesWarning.js +16 -16
  21. package/lib/Chunk.js +252 -252
  22. package/lib/ChunkRenderError.js +17 -17
  23. package/lib/ChunkTemplate.js +37 -37
  24. package/lib/CompatibilityPlugin.js +42 -42
  25. package/lib/Compilation.js +891 -891
  26. package/lib/Compiler.js +407 -407
  27. package/lib/ConcatSource.js +5 -5
  28. package/lib/ConstPlugin.js +54 -54
  29. package/lib/ContextModule.js +130 -130
  30. package/lib/ContextModuleFactory.js +132 -132
  31. package/lib/ContextReplacementPlugin.js +93 -93
  32. package/lib/CriticalDependenciesWarning.js +24 -24
  33. package/lib/DefinePlugin.js +126 -126
  34. package/lib/DelegatedModule.js +69 -69
  35. package/lib/DelegatedModuleFactoryPlugin.js +51 -51
  36. package/lib/DelegatedPlugin.js +21 -21
  37. package/lib/DependenciesBlock.js +57 -57
  38. package/lib/DependenciesBlockVariable.js +41 -41
  39. package/lib/Dependency.js +54 -54
  40. package/lib/DllEntryPlugin.js +32 -32
  41. package/lib/DllModule.js +55 -55
  42. package/lib/DllModuleFactory.js +18 -18
  43. package/lib/DllPlugin.js +30 -30
  44. package/lib/DllReferencePlugin.js +26 -26
  45. package/lib/EntryModuleNotFoundError.js +15 -15
  46. package/lib/EntryOptionPlugin.js +28 -28
  47. package/lib/EnvironmentPlugin.js +28 -28
  48. package/lib/EvalDevToolModulePlugin.js +17 -17
  49. package/lib/EvalDevToolModuleTemplatePlugin.js +29 -29
  50. package/lib/EvalSourceMapDevToolModuleTemplatePlugin.js +68 -68
  51. package/lib/EvalSourceMapDevToolPlugin.js +25 -25
  52. package/lib/ExtendedAPIPlugin.js +45 -45
  53. package/lib/ExternalModule.js +89 -89
  54. package/lib/ExternalModuleFactoryPlugin.js +86 -86
  55. package/lib/ExternalsPlugin.js +16 -16
  56. package/lib/FunctionModulePlugin.js +18 -18
  57. package/lib/FunctionModuleTemplatePlugin.js +39 -39
  58. package/lib/HotModuleReplacement.runtime.js +486 -486
  59. package/lib/HotModuleReplacementPlugin.js +223 -223
  60. package/lib/HotUpdateChunkTemplate.js +28 -28
  61. package/lib/IgnorePlugin.js +32 -32
  62. package/lib/JsonpChunkTemplatePlugin.js +26 -26
  63. package/lib/JsonpExportMainTemplatePlugin.js +28 -28
  64. package/lib/JsonpHotUpdateChunkTemplatePlugin.js +26 -26
  65. package/lib/JsonpMainTemplate.runtime.js +56 -56
  66. package/lib/JsonpMainTemplatePlugin.js +162 -162
  67. package/lib/JsonpTemplatePlugin.js +17 -17
  68. package/lib/LibManifestPlugin.js +49 -49
  69. package/lib/LibraryTemplatePlugin.js +77 -77
  70. package/lib/LoaderTargetPlugin.js +16 -16
  71. package/lib/MainTemplate.js +169 -169
  72. package/lib/MemoryOutputFileSystem.js +5 -5
  73. package/lib/Module.js +116 -116
  74. package/lib/ModuleFilenameHelpers.js +157 -157
  75. package/lib/ModuleNotFoundError.js +17 -17
  76. package/lib/ModuleParseError.js +26 -26
  77. package/lib/ModuleParserHelpers.js +21 -21
  78. package/lib/ModuleReason.js +9 -9
  79. package/lib/ModuleTemplate.js +23 -23
  80. package/lib/MovedToPluginWarningPlugin.js +17 -17
  81. package/lib/MultiCompiler.js +166 -166
  82. package/lib/MultiEntryPlugin.js +31 -31
  83. package/lib/MultiModule.js +71 -71
  84. package/lib/MultiModuleFactory.js +18 -18
  85. package/lib/NamedModulesPlugin.js +21 -21
  86. package/lib/NewWatchingPlugin.js +12 -12
  87. package/lib/NoErrorsPlugin.js +18 -18
  88. package/lib/NodeStuffPlugin.js +99 -99
  89. package/lib/NormalModule.js +322 -322
  90. package/lib/NormalModuleFactory.js +171 -171
  91. package/lib/NormalModuleReplacementPlugin.js +40 -40
  92. package/lib/NullFactory.js +10 -10
  93. package/lib/OldWatchingPlugin.js +14 -14
  94. package/lib/OptionsApply.js +10 -10
  95. package/lib/OriginalSource.js +5 -5
  96. package/lib/Parser.js +938 -938
  97. package/lib/PrefetchPlugin.js +25 -25
  98. package/lib/ProgressPlugin.js +80 -80
  99. package/lib/ProvidePlugin.js +48 -48
  100. package/lib/RawModule.js +65 -65
  101. package/lib/RawSource.js +5 -5
  102. package/lib/RecordIdsPlugin.js +130 -130
  103. package/lib/RequestShortener.js +56 -56
  104. package/lib/RequireJsStuffPlugin.js +38 -38
  105. package/lib/ResolverPlugin.js +34 -34
  106. package/lib/SetVarMainTemplatePlugin.js +36 -36
  107. package/lib/SingleEntryPlugin.js +24 -24
  108. package/lib/Source.js +5 -5
  109. package/lib/SourceMapDevToolModuleOptionsPlugin.js +33 -33
  110. package/lib/SourceMapDevToolPlugin.js +168 -168
  111. package/lib/SourceMapSource.js +5 -5
  112. package/lib/Stats.js +732 -732
  113. package/lib/Template.js +119 -119
  114. package/lib/TemplatedPathPlugin.js +111 -111
  115. package/lib/UmdMainTemplatePlugin.js +146 -146
  116. package/lib/UnsupportedFeatureWarning.js +14 -14
  117. package/lib/WarnCaseSensitiveModulesPlugin.js +27 -27
  118. package/lib/WatchIgnorePlugin.js +45 -45
  119. package/lib/WebpackOptionsApply.js +376 -376
  120. package/lib/WebpackOptionsDefaulter.js +112 -112
  121. package/lib/dependencies/AMDDefineDependency.js +63 -63
  122. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +240 -240
  123. package/lib/dependencies/AMDPlugin.js +115 -115
  124. package/lib/dependencies/AMDRequireArrayDependency.js +34 -34
  125. package/lib/dependencies/AMDRequireContextDependency.js +18 -18
  126. package/lib/dependencies/AMDRequireDependenciesBlock.js +25 -25
  127. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +145 -145
  128. package/lib/dependencies/AMDRequireDependency.js +64 -64
  129. package/lib/dependencies/AMDRequireItemDependency.js +17 -17
  130. package/lib/dependencies/CommonJsPlugin.js +93 -93
  131. package/lib/dependencies/CommonJsRequireContextDependency.js +18 -18
  132. package/lib/dependencies/CommonJsRequireDependency.js +17 -17
  133. package/lib/dependencies/CommonJsRequireDependencyParserPlugin.js +91 -91
  134. package/lib/dependencies/ConstDependency.js +29 -29
  135. package/lib/dependencies/ContextDependency.js +24 -24
  136. package/lib/dependencies/ContextDependencyHelpers.js +34 -34
  137. package/lib/dependencies/ContextDependencyTemplateAsId.js +22 -22
  138. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +31 -31
  139. package/lib/dependencies/ContextElementDependency.js +17 -17
  140. package/lib/dependencies/DelegatedSourceDependency.js +14 -14
  141. package/lib/dependencies/DepBlockHelpers.js +41 -41
  142. package/lib/dependencies/DllEntryDependency.js +17 -17
  143. package/lib/dependencies/LabeledExportsDependency.js +21 -21
  144. package/lib/dependencies/LabeledModuleDependency.js +36 -36
  145. package/lib/dependencies/LabeledModuleDependencyParserPlugin.js +76 -76
  146. package/lib/dependencies/LabeledModulesPlugin.js +26 -26
  147. package/lib/dependencies/LoaderDependency.js +14 -14
  148. package/lib/dependencies/LoaderPlugin.js +61 -61
  149. package/lib/dependencies/LocalModule.js +19 -19
  150. package/lib/dependencies/LocalModuleDependency.js +23 -23
  151. package/lib/dependencies/LocalModulesHelpers.js +43 -43
  152. package/lib/dependencies/ModuleDependency.js +20 -20
  153. package/lib/dependencies/ModuleDependencyTemplateAsId.js +22 -22
  154. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +22 -22
  155. package/lib/dependencies/ModuleHotAcceptDependency.js +18 -18
  156. package/lib/dependencies/ModuleHotDeclineDependency.js +18 -18
  157. package/lib/dependencies/MultiEntryDependency.js +16 -16
  158. package/lib/dependencies/NullDependency.js +17 -17
  159. package/lib/dependencies/NullDependencyTemplate.js +8 -8
  160. package/lib/dependencies/PrefetchDependency.js +14 -14
  161. package/lib/dependencies/RequireContextDependency.js +17 -17
  162. package/lib/dependencies/RequireContextDependencyParserPlugin.js +33 -33
  163. package/lib/dependencies/RequireContextPlugin.js +64 -64
  164. package/lib/dependencies/RequireEnsureDependenciesBlock.js +20 -20
  165. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +66 -66
  166. package/lib/dependencies/RequireEnsureDependency.js +29 -29
  167. package/lib/dependencies/RequireEnsureItemDependency.js +16 -16
  168. package/lib/dependencies/RequireEnsurePlugin.js +38 -38
  169. package/lib/dependencies/RequireHeaderDependency.js +25 -25
  170. package/lib/dependencies/RequireIncludeDependency.js +25 -25
  171. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +18 -18
  172. package/lib/dependencies/RequireIncludePlugin.js +31 -31
  173. package/lib/dependencies/RequireResolveContextDependency.js +18 -18
  174. package/lib/dependencies/RequireResolveDependency.js +17 -17
  175. package/lib/dependencies/RequireResolveDependencyParserPlugin.js +69 -69
  176. package/lib/dependencies/RequireResolveHeaderDependency.js +25 -25
  177. package/lib/dependencies/SingleEntryDependency.js +14 -14
  178. package/lib/dependencies/TemplateArgumentDependency.js +26 -26
  179. package/lib/dependencies/WebpackMissingModule.js +23 -23
  180. package/lib/dependencies/getFunctionExpression.js +43 -43
  181. package/lib/node/NodeChunkTemplatePlugin.js +22 -22
  182. package/lib/node/NodeEnvironmentPlugin.js +25 -25
  183. package/lib/node/NodeHotUpdateChunkTemplatePlugin.js +24 -24
  184. package/lib/node/NodeMainTemplate.runtime.js +20 -20
  185. package/lib/node/NodeMainTemplateAsync.runtime.js +34 -34
  186. package/lib/node/NodeMainTemplatePlugin.js +164 -164
  187. package/lib/node/NodeOutputFileSystem.js +17 -17
  188. package/lib/node/NodeSourcePlugin.js +85 -75
  189. package/lib/node/NodeTargetPlugin.js +12 -12
  190. package/lib/node/NodeTemplatePlugin.js +21 -21
  191. package/lib/node/NodeWatchFileSystem.js +65 -65
  192. package/lib/node/OldNodeWatchFileSystem.js +265 -265
  193. package/lib/optimize/AggressiveMergingPlugin.js +115 -115
  194. package/lib/optimize/CommonsChunkPlugin.js +178 -178
  195. package/lib/optimize/DedupePlugin.js +227 -227
  196. package/lib/optimize/FlagIncludedChunksPlugin.js +24 -24
  197. package/lib/optimize/LimitChunkCountPlugin.js +55 -55
  198. package/lib/optimize/MergeDuplicateChunksPlugin.js +30 -30
  199. package/lib/optimize/MinChunkSizePlugin.js +61 -61
  200. package/lib/optimize/OccurenceOrderPlugin.js +5 -5
  201. package/lib/optimize/OccurrenceOrderPlugin.js +91 -91
  202. package/lib/optimize/RemoveEmptyChunksPlugin.js +19 -19
  203. package/lib/optimize/RemoveParentModulesPlugin.js +50 -50
  204. package/lib/optimize/UglifyJsPlugin.js +146 -146
  205. package/lib/removeAndDo.js +13 -13
  206. package/lib/web/WebEnvironmentPlugin.js +16 -16
  207. package/lib/webpack.js +113 -113
  208. package/lib/webpack.web.js +27 -27
  209. package/lib/webworker/WebWorkerChunkTemplatePlugin.js +26 -26
  210. package/lib/webworker/WebWorkerMainTemplatePlugin.js +78 -78
  211. package/lib/webworker/WebWorkerTemplatePlugin.js +15 -15
  212. package/package.json +4 -4
package/lib/Parser.js CHANGED
@@ -1,938 +1,938 @@
1
- /*
2
- MIT License http://www.opensource.org/licenses/mit-license.php
3
- Author Tobias Koppers @sokra
4
- */
5
- var acorn = require("acorn");
6
- var Tapable = require("tapable");
7
- var BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
8
-
9
- function Parser(options) {
10
- Tapable.call(this);
11
- this.options = options;
12
- this.initializeEvaluating();
13
- }
14
- module.exports = Parser;
15
-
16
- // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
17
-
18
- Parser.prototype = Object.create(Tapable.prototype);
19
- Parser.prototype.constructor = Parser;
20
-
21
- Parser.prototype.initializeEvaluating = function() {
22
- function joinRanges(startRange, endRange) {
23
- if(!endRange) return startRange;
24
- if(!startRange) return endRange;
25
- return [startRange[0], endRange[1]];
26
- }
27
- this.plugin("evaluate Literal", function(expr) {
28
- switch(typeof expr.value) {
29
- case "number":
30
- return new BasicEvaluatedExpression().setNumber(expr.value).setRange(expr.range);
31
- case "string":
32
- return new BasicEvaluatedExpression().setString(expr.value).setRange(expr.range);
33
- case "boolean":
34
- return new BasicEvaluatedExpression().setBoolean(expr.value).setRange(expr.range);
35
- }
36
- if(expr.value === null)
37
- return new BasicEvaluatedExpression().setNull().setRange(expr.range);
38
- if(expr.value instanceof RegExp)
39
- return new BasicEvaluatedExpression().setRegExp(expr.value).setRange(expr.range);
40
- });
41
- this.plugin("evaluate LogicalExpression", function(expr) {
42
- var left;
43
- var leftAsBool;
44
- var right;
45
- if(expr.operator === "&&") {
46
- left = this.evaluateExpression(expr.left);
47
- leftAsBool = left && left.asBool();
48
- if(leftAsBool === false) return left.setRange(expr.range);
49
- if(leftAsBool !== true) return;
50
- right = this.evaluateExpression(expr.right);
51
- return right.setRange(expr.range);
52
- } else if(expr.operator === "||") {
53
- left = this.evaluateExpression(expr.left);
54
- leftAsBool = left && left.asBool();
55
- if(leftAsBool === true) return left.setRange(expr.range);
56
- if(leftAsBool !== false) return;
57
- right = this.evaluateExpression(expr.right);
58
- return right.setRange(expr.range);
59
- }
60
- });
61
- this.plugin("evaluate BinaryExpression", function(expr) {
62
- var left;
63
- var right;
64
- var res;
65
- if(expr.operator === "+") {
66
- left = this.evaluateExpression(expr.left);
67
- right = this.evaluateExpression(expr.right);
68
- if(!left || !right) return;
69
- res = new BasicEvaluatedExpression();
70
- if(left.isString()) {
71
- if(right.isString()) {
72
- res.setString(left.string + right.string);
73
- } else if(right.isNumber()) {
74
- res.setString(left.string + right.number);
75
- } else if(right.isWrapped() && right.prefix && right.prefix.isString()) {
76
- res.setWrapped(
77
- new BasicEvaluatedExpression()
78
- .setString(left.string + right.prefix.string)
79
- .setRange(joinRanges(left.range, right.prefix.range)),
80
- right.postfix);
81
- } else {
82
- res.setWrapped(left, null);
83
- }
84
- } else if(left.isNumber()) {
85
- if(right.isString()) {
86
- res.setString(left.number + right.string);
87
- } else if(right.isNumber()) {
88
- res.setNumber(left.number + right.number);
89
- }
90
- } else if(left.isWrapped()) {
91
- if(left.postfix && left.postfix.isString() && right.isString()) {
92
- res.setWrapped(left.prefix,
93
- new BasicEvaluatedExpression()
94
- .setString(left.postfix.string + right.string)
95
- .setRange(joinRanges(left.postfix.range, right.range))
96
- );
97
- } else if(left.postfix && left.postfix.isString() && right.isNumber()) {
98
- res.setWrapped(left.prefix,
99
- new BasicEvaluatedExpression()
100
- .setString(left.postfix.string + right.number)
101
- .setRange(joinRanges(left.postfix.range, right.range))
102
- );
103
- } else if(right.isString()) {
104
- res.setWrapped(left.prefix, right);
105
- } else if(right.isNumber()) {
106
- res.setWrapped(left.prefix,
107
- new BasicEvaluatedExpression()
108
- .setString(right.number + "")
109
- .setRange(right.range));
110
- } else {
111
- res.setWrapped(left.prefix, new BasicEvaluatedExpression());
112
- }
113
- } else {
114
- if(right.isString()) {
115
- res.setWrapped(null, right);
116
- }
117
- }
118
- res.setRange(expr.range);
119
- return res;
120
- } else if(expr.operator === "-") {
121
- left = this.evaluateExpression(expr.left);
122
- right = this.evaluateExpression(expr.right);
123
- if(!left || !right) return;
124
- if(!left.isNumber() || !right.isNumber()) return;
125
- res = new BasicEvaluatedExpression();
126
- res.setNumber(left.number - right.number);
127
- res.setRange(expr.range);
128
- return res;
129
- } else if(expr.operator === "*") {
130
- left = this.evaluateExpression(expr.left);
131
- right = this.evaluateExpression(expr.right);
132
- if(!left || !right) return;
133
- if(!left.isNumber() || !right.isNumber()) return;
134
- res = new BasicEvaluatedExpression();
135
- res.setNumber(left.number * right.number);
136
- res.setRange(expr.range);
137
- return res;
138
- } else if(expr.operator === "/") {
139
- left = this.evaluateExpression(expr.left);
140
- right = this.evaluateExpression(expr.right);
141
- if(!left || !right) return;
142
- if(!left.isNumber() || !right.isNumber()) return;
143
- res = new BasicEvaluatedExpression();
144
- res.setNumber(left.number / right.number);
145
- res.setRange(expr.range);
146
- return res;
147
- } else if(expr.operator === "==" || expr.operator === "===") {
148
- left = this.evaluateExpression(expr.left);
149
- right = this.evaluateExpression(expr.right);
150
- if(!left || !right) return;
151
- res = new BasicEvaluatedExpression();
152
- res.setRange(expr.range);
153
- if(left.isString() && right.isString()) {
154
- return res.setBoolean(left.string === right.string);
155
- } else if(left.isNumber() && right.isNumber()) {
156
- return res.setBoolean(left.number === right.number);
157
- } else if(left.isBoolean() && right.isBoolean()) {
158
- return res.setBoolean(left.bool === right.bool);
159
- }
160
- } else if(expr.operator === "!=" || expr.operator === "!==") {
161
- left = this.evaluateExpression(expr.left);
162
- right = this.evaluateExpression(expr.right);
163
- if(!left || !right) return;
164
- res = new BasicEvaluatedExpression();
165
- res.setRange(expr.range);
166
- if(left.isString() && right.isString()) {
167
- return res.setBoolean(left.string !== right.string);
168
- } else if(left.isNumber() && right.isNumber()) {
169
- return res.setBoolean(left.number !== right.number);
170
- } else if(left.isBoolean() && right.isBoolean()) {
171
- return res.setBoolean(left.bool !== right.bool);
172
- }
173
- }
174
- });
175
- this.plugin("evaluate UnaryExpression", function(expr) {
176
- if(expr.operator === "typeof") {
177
- var res;
178
- if(expr.argument.type === "Identifier") {
179
- var name = this.scope.renames["$" + expr.argument.name] || expr.argument.name;
180
- if(this.scope.definitions.indexOf(name) === -1) {
181
- res = this.applyPluginsBailResult("evaluate typeof " + name, expr);
182
- if(res !== undefined) return res;
183
- }
184
- }
185
- if(expr.argument.type === "MemberExpression") {
186
- var expression = expr.argument;
187
- var exprName = [];
188
- while(expression.type === "MemberExpression" && !expression.computed) {
189
- exprName.unshift(this.scope.renames["$" + expression.property.name] || expression.property.name);
190
- expression = expression.object;
191
- }
192
- if(expression.type === "Identifier") {
193
- exprName.unshift(this.scope.renames["$" + expression.name] || expression.name);
194
- if(this.scope.definitions.indexOf(name) === -1) {
195
- exprName = exprName.join(".");
196
- res = this.applyPluginsBailResult("evaluate typeof " + exprName, expr);
197
- if(res !== undefined) return res;
198
- }
199
- }
200
- }
201
- if(expr.argument.type === "FunctionExpression") {
202
- return new BasicEvaluatedExpression().setString("function").setRange(expr.range);
203
- }
204
- var arg = this.evaluateExpression(expr.argument);
205
- if(arg.isString() || arg.isWrapped()) return new BasicEvaluatedExpression().setString("string").setRange(expr.range);
206
- else if(arg.isNumber()) return new BasicEvaluatedExpression().setString("number").setRange(expr.range);
207
- else if(arg.isBoolean()) return new BasicEvaluatedExpression().setString("boolean").setRange(expr.range);
208
- else if(arg.isArray() || arg.isConstArray() || arg.isRegExp()) return new BasicEvaluatedExpression().setString("object").setRange(expr.range);
209
- } else if(expr.operator === "!") {
210
- var argument = this.evaluateExpression(expr.argument);
211
- if(!argument) return;
212
- if(argument.isBoolean()) {
213
- return new BasicEvaluatedExpression().setBoolean(!argument.bool).setRange(expr.range);
214
- } else if(argument.isString()) {
215
- return new BasicEvaluatedExpression().setBoolean(!argument.string).setRange(expr.range);
216
- } else if(argument.isNumber()) {
217
- return new BasicEvaluatedExpression().setBoolean(!argument.number).setRange(expr.range);
218
- }
219
- }
220
- });
221
- this.plugin("evaluate typeof undefined", function(expr) {
222
- return new BasicEvaluatedExpression().setString("undefined").setRange(expr.range);
223
- });
224
- this.plugin("evaluate Identifier", function(expr) {
225
- var name = this.scope.renames["$" + expr.name] || expr.name;
226
- if(this.scope.definitions.indexOf(expr.name) === -1) {
227
- var result = this.applyPluginsBailResult("evaluate Identifier " + name, expr);
228
- if(result) return result;
229
- return new BasicEvaluatedExpression().setIdentifier(name).setRange(expr.range);
230
- } else {
231
- return this.applyPluginsBailResult("evaluate defined Identifier " + name, expr);
232
- }
233
- });
234
- this.plugin("evaluate MemberExpression", function(expression) {
235
- var expr = expression;
236
- var exprName = [];
237
- while(expr.type === "MemberExpression" && !expr.computed) {
238
- exprName.unshift(expr.property.name);
239
- expr = expr.object;
240
- }
241
- if(expr.type === "Identifier") {
242
- var name = this.scope.renames["$" + expr.name] || expr.name;
243
- if(this.scope.definitions.indexOf(name) === -1) {
244
- exprName.unshift(name);
245
- exprName = exprName.join(".");
246
- if(this.scope.definitions.indexOf(expr.name) === -1) {
247
- var result = this.applyPluginsBailResult("evaluate Identifier " + exprName, expression);
248
- if(result) return result;
249
- return new BasicEvaluatedExpression().setIdentifier(exprName).setRange(expression.range);
250
- } else {
251
- return this.applyPluginsBailResult("evaluate defined Identifier " + exprName, expression);
252
- }
253
- }
254
- }
255
- });
256
- this.plugin("evaluate CallExpression", function(expr) {
257
- if(expr.callee.type !== "MemberExpression") return;
258
- if(expr.callee.computed) return;
259
- var param = this.evaluateExpression(expr.callee.object);
260
- if(!param) return;
261
- return this.applyPluginsBailResult("evaluate CallExpression ." + expr.callee.property.name, expr, param);
262
- });
263
- this.plugin("evaluate CallExpression .replace", function(expr, param) {
264
- if(!param.isString()) return;
265
- if(expr.arguments.length !== 2) return;
266
- var arg1 = this.evaluateExpression(expr.arguments[0]);
267
- var arg2 = this.evaluateExpression(expr.arguments[1]);
268
- if(!arg1.isString() && !arg1.isRegExp()) return;
269
- arg1 = arg1.regExp || arg1.string;
270
- if(!arg2.isString()) return;
271
- arg2 = arg2.string;
272
- return new BasicEvaluatedExpression().setString(param.string.replace(arg1, arg2)).setRange(expr.range);
273
- });
274
- ["substr", "substring"].forEach(function(fn) {
275
- this.plugin("evaluate CallExpression ." + fn, function(expr, param) {
276
- if(!param.isString()) return;
277
- var arg1;
278
- var result, str = param.string;
279
- switch(expr.arguments.length) {
280
- case 1:
281
- arg1 = this.evaluateExpression(expr.arguments[0]);
282
- if(!arg1.isNumber()) return;
283
- result = str[fn](arg1.number);
284
- break;
285
- case 2:
286
- arg1 = this.evaluateExpression(expr.arguments[0]);
287
- var arg2 = this.evaluateExpression(expr.arguments[1]);
288
- if(!arg1.isNumber()) return;
289
- if(!arg2.isNumber()) return;
290
- result = str[fn](arg1.number, arg2.number);
291
- break;
292
- default:
293
- return;
294
- }
295
- return new BasicEvaluatedExpression().setString(result).setRange(expr.range);
296
- });
297
- }, this);
298
- this.plugin("evaluate CallExpression .split", function(expr, param) {
299
- if(!param.isString()) return;
300
- if(expr.arguments.length !== 1) return;
301
- var result;
302
- var arg = this.evaluateExpression(expr.arguments[0]);
303
- if(arg.isString()) {
304
- result = param.string.split(arg.string);
305
- } else if(arg.isRegExp()) {
306
- result = param.string.split(arg.regExp);
307
- } else return;
308
- return new BasicEvaluatedExpression().setArray(result).setRange(expr.range);
309
- });
310
- this.plugin("evaluate ConditionalExpression", function(expr) {
311
- var condition = this.evaluateExpression(expr.test);
312
- var conditionValue = condition.asBool();
313
- var res;
314
- if(conditionValue === undefined) {
315
- var consequent = this.evaluateExpression(expr.consequent);
316
- var alternate = this.evaluateExpression(expr.alternate);
317
- if(!consequent || !alternate) return;
318
- res = new BasicEvaluatedExpression();
319
- if(consequent.isConditional())
320
- res.setOptions(consequent.options);
321
- else
322
- res.setOptions([consequent]);
323
- if(alternate.isConditional())
324
- res.addOptions(alternate.options);
325
- else
326
- res.addOptions([alternate]);
327
- } else {
328
- res = this.evaluateExpression(conditionValue ? expr.consequent : expr.alternate);
329
- }
330
- res.setRange(expr.range);
331
- return res;
332
- });
333
- this.plugin("evaluate ArrayExpression", function(expr) {
334
- var items = expr.elements.map(function(element) {
335
- return element !== null && this.evaluateExpression(element);
336
- }, this);
337
- if(items.filter(function(i) {
338
- return !i;
339
- }).length > 0) return;
340
- return new BasicEvaluatedExpression().setItems(items).setRange(expr.range);
341
- });
342
- };
343
-
344
- Parser.prototype.getRenameIdentifier = function getRenameIdentifier(expr) {
345
- var result = this.evaluateExpression(expr);
346
- if(!result) return;
347
- if(result.isIdentifier()) return result.identifier;
348
- return;
349
- };
350
-
351
- Parser.prototype.walkClass = function walkClass(classy) {
352
- if(classy.superClass)
353
- this.walkExpression(classy.superClass);
354
- if(classy.body && classy.body.type === "ClassBody") {
355
- classy.body.body.forEach(function(methodDefinition) {
356
- if(methodDefinition.type === "MethodDefinition")
357
- this.walkMethodDefinition(methodDefinition);
358
- }, this);
359
- }
360
- };
361
-
362
- Parser.prototype.walkMethodDefinition = function walkMethodDefinition(methodDefinition) {
363
- if(methodDefinition.computed && methodDefinition.key)
364
- this.walkExpression(methodDefinition.key);
365
- if(methodDefinition.value)
366
- this.walkExpression(methodDefinition.value);
367
- };
368
-
369
- Parser.prototype.walkStatements = function walkStatements(statements) {
370
- statements.forEach(function(statement) {
371
- this.walkStatement(statement);
372
- }, this);
373
- };
374
-
375
- Parser.prototype.walkStatement = function walkStatement(statement) {
376
- if(this.applyPluginsBailResult("statement", statement) !== undefined) return;
377
- if(this["walk" + statement.type])
378
- this["walk" + statement.type](statement);
379
- };
380
-
381
- // Real Statements
382
- Parser.prototype.walkBlockStatement = function walkBlockStatement(statement) {
383
- this.walkStatements(statement.body);
384
- };
385
-
386
- Parser.prototype.walkExpressionStatement = function walkExpressionStatement(statement) {
387
- this.walkExpression(statement.expression);
388
- };
389
-
390
- Parser.prototype.walkIfStatement = function walkIfStatement(statement) {
391
- var result = this.applyPluginsBailResult("statement if", statement);
392
- if(result === undefined) {
393
- this.walkExpression(statement.test);
394
- this.walkStatement(statement.consequent);
395
- if(statement.alternate)
396
- this.walkStatement(statement.alternate);
397
- } else {
398
- if(result)
399
- this.walkStatement(statement.consequent);
400
- else if(statement.alternate)
401
- this.walkStatement(statement.alternate);
402
- }
403
- };
404
-
405
- Parser.prototype.walkLabeledStatement = function walkLabeledStatement(statement) {
406
- var result = this.applyPluginsBailResult("label " + statement.label.name, statement);
407
- if(result !== true)
408
- this.walkStatement(statement.body);
409
- };
410
-
411
- Parser.prototype.walkWithStatement = function walkWithStatement(statement) {
412
- this.walkExpression(statement.object);
413
- this.walkStatement(statement.body);
414
- };
415
-
416
- Parser.prototype.walkSwitchStatement = function walkSwitchStatement(statement) {
417
- this.walkExpression(statement.discriminant);
418
- this.walkSwitchCases(statement.cases);
419
- };
420
-
421
- Parser.prototype.walkReturnStatement =
422
- Parser.prototype.walkThrowStatement = function walkArgumentStatement(statement) {
423
- if(statement.argument)
424
- this.walkExpression(statement.argument);
425
- };
426
-
427
- Parser.prototype.walkTryStatement = function walkTryStatement(statement) {
428
- if(this.scope.inTry) {
429
- this.walkStatement(statement.block);
430
- } else {
431
- this.scope.inTry = true;
432
- this.walkStatement(statement.block);
433
- this.scope.inTry = false;
434
- }
435
- if(statement.handler)
436
- this.walkCatchClause(statement.handler);
437
- if(statement.finalizer)
438
- this.walkStatement(statement.finalizer);
439
- };
440
-
441
- Parser.prototype.walkWhileStatement =
442
- Parser.prototype.walkDoWhileStatement = function walkLoopStatement(statement) {
443
- this.walkExpression(statement.test);
444
- this.walkStatement(statement.body);
445
- };
446
-
447
- Parser.prototype.walkForStatement = function walkForStatement(statement) {
448
- if(statement.init) {
449
- if(statement.init.type === "VariableDeclaration")
450
- this.walkStatement(statement.init);
451
- else
452
- this.walkExpression(statement.init);
453
- }
454
- if(statement.test)
455
- this.walkExpression(statement.test);
456
- if(statement.update)
457
- this.walkExpression(statement.update);
458
- this.walkStatement(statement.body);
459
- };
460
-
461
- Parser.prototype.walkForInStatement = function walkForInStatement(statement) {
462
- if(statement.left.type === "VariableDeclaration")
463
- this.walkStatement(statement.left);
464
- else
465
- this.walkExpression(statement.left);
466
- this.walkExpression(statement.right);
467
- this.walkStatement(statement.body);
468
- };
469
-
470
- Parser.prototype.walkForOfStatement = function walkForOfStatement(statement) {
471
- if(statement.left.type === "VariableDeclaration")
472
- this.walkStatement(statement.left);
473
- else
474
- this.walkExpression(statement.left);
475
- this.walkExpression(statement.right);
476
- this.walkStatement(statement.body);
477
- };
478
-
479
- // Declarations
480
- Parser.prototype.walkFunctionDeclaration = function walkFunctionDeclaration(statement) {
481
- this.scope.renames["$" + statement.id.name] = undefined;
482
- this.scope.definitions.push(statement.id.name);
483
- this.inScope(statement.params, function() {
484
- if(statement.body.type === "BlockStatement")
485
- this.walkStatement(statement.body);
486
- else
487
- this.walkExpression(statement.body);
488
- }.bind(this));
489
- };
490
-
491
- Parser.prototype.walkVariableDeclaration = function walkVariableDeclaration(statement) {
492
- if(statement.declarations)
493
- this.walkVariableDeclarators(statement.declarations);
494
- };
495
-
496
- Parser.prototype.walkClassDeclaration = function walkClassDeclaration(statement) {
497
- this.walkClass(statement);
498
- };
499
-
500
- Parser.prototype.walkSwitchCases = function walkSwitchCases(switchCases) {
501
- switchCases.forEach(function(switchCase) {
502
- if(switchCase.test)
503
- this.walkExpression(switchCase.test);
504
- this.walkStatements(switchCase.consequent);
505
- }, this);
506
- };
507
-
508
- Parser.prototype.walkCatchClause = function walkCatchClause(catchClause) {
509
- if(catchClause.guard)
510
- this.walkExpression(catchClause.guard);
511
- this.inScope([catchClause.param], function() {
512
- this.walkStatement(catchClause.body);
513
- }.bind(this));
514
- };
515
-
516
- Parser.prototype.walkVariableDeclarators = function walkVariableDeclarators(declarators) {
517
- declarators.forEach(function(declarator) {
518
- switch(declarator.type) {
519
- case "VariableDeclarator":
520
- var renameIdentifier = declarator.init && this.getRenameIdentifier(declarator.init);
521
- if(renameIdentifier && declarator.id.type === "Identifier" && this.applyPluginsBailResult("can-rename " + renameIdentifier, declarator.init)) {
522
- // renaming with "var a = b;"
523
- if(!this.applyPluginsBailResult("rename " + renameIdentifier, declarator.init)) {
524
- this.scope.renames["$" + declarator.id.name] = this.scope.renames["$" + renameIdentifier] || renameIdentifier;
525
- var idx = this.scope.definitions.indexOf(declarator.id.name);
526
- if(idx >= 0) this.scope.definitions.splice(idx, 1);
527
- }
528
- } else if(declarator.id.type === "Identifier" && !this.applyPluginsBailResult("var " + declarator.id.name, declarator)) {
529
- this.scope.renames["$" + declarator.id.name] = undefined;
530
- this.scope.definitions.push(declarator.id.name);
531
- if(declarator.init)
532
- this.walkExpression(declarator.init);
533
- } else {
534
- this.walkExpression(declarator.id);
535
- if(declarator.init)
536
- this.walkExpression(declarator.init);
537
- }
538
- break;
539
- }
540
- }, this);
541
- };
542
-
543
- Parser.prototype.walkExpressions = function walkExpressions(expressions) {
544
- expressions.forEach(function(expression) {
545
- if(expression)
546
- this.walkExpression(expression);
547
- }, this);
548
- };
549
-
550
- Parser.prototype.walkExpression = function walkExpression(expression) {
551
- if(this["walk" + expression.type])
552
- return this["walk" + expression.type](expression);
553
- };
554
-
555
- Parser.prototype.walkArrayExpression = function walkArrayExpression(expression) {
556
- if(expression.elements)
557
- this.walkExpressions(expression.elements);
558
- };
559
-
560
- Parser.prototype.walkSpreadElement = function walkSpreadElement(expression) {
561
- if(expression.argument)
562
- this.walkExpression(expression.argument);
563
- };
564
-
565
- Parser.prototype.walkObjectExpression = function walkObjectExpression(expression) {
566
- expression.properties.forEach(function(prop) {
567
- if(prop.computed)
568
- this.walkExpression(prop.key)
569
- this.walkExpression(prop.value);
570
- }, this);
571
- };
572
-
573
- Parser.prototype.walkFunctionExpression = function walkFunctionExpression(expression) {
574
- this.inScope(expression.params, function() {
575
- if(expression.body.type === "BlockStatement")
576
- this.walkStatement(expression.body);
577
- else
578
- this.walkExpression(expression.body);
579
- }.bind(this));
580
- };
581
-
582
- Parser.prototype.walkArrowFunctionExpression = function walkArrowFunctionExpression(expression) {
583
- this.inScope(expression.params, function() {
584
- if(expression.body.type === "BlockStatement")
585
- this.walkStatement(expression.body);
586
- else
587
- this.walkExpression(expression.body);
588
- }.bind(this));
589
- };
590
-
591
- Parser.prototype.walkSequenceExpression = function walkSequenceExpression(expression) {
592
- if(expression.expressions)
593
- this.walkExpressions(expression.expressions);
594
- };
595
-
596
- Parser.prototype.walkUpdateExpression = function walkUpdateExpression(expression) {
597
- this.walkExpression(expression.argument);
598
- };
599
-
600
- Parser.prototype.walkUnaryExpression = function walkUnaryExpression(expression) {
601
- if(expression.operator === "typeof") {
602
- var expr = expression.argument;
603
- var exprName = [];
604
- while(expr.type === "MemberExpression" && !expr.computed) {
605
- exprName.unshift(expr.property.name);
606
- expr = expr.object;
607
- }
608
- if(expr.type === "Identifier" && this.scope.definitions.indexOf(expr.name) === -1) {
609
- exprName.unshift(this.scope.renames["$" + expr.name] || expr.name);
610
- exprName = exprName.join(".");
611
- var result = this.applyPluginsBailResult("typeof " + exprName, expression);
612
- if(result === true)
613
- return;
614
- }
615
- }
616
- this.walkExpression(expression.argument);
617
- };
618
-
619
- Parser.prototype.walkBinaryExpression =
620
- Parser.prototype.walkLogicalExpression = function walkLeftRightExpression(expression) {
621
- this.walkExpression(expression.left);
622
- this.walkExpression(expression.right);
623
- };
624
-
625
- Parser.prototype.walkAssignmentExpression = function walkAssignmentExpression(expression) {
626
- var renameIdentifier = this.getRenameIdentifier(expression.right);
627
- if(expression.left.type === "Identifier" && renameIdentifier && this.applyPluginsBailResult("can-rename " + renameIdentifier, expression.right)) {
628
- // renaming "a = b;"
629
- if(!this.applyPluginsBailResult("rename " + renameIdentifier, expression.right)) {
630
- this.scope.renames["$" + expression.left.name] = renameIdentifier;
631
- var idx = this.scope.definitions.indexOf(expression.left.name);
632
- if(idx >= 0) this.scope.definitions.splice(idx, 1);
633
- }
634
- } else if(expression.left.type === "Identifier") {
635
- if(!this.applyPluginsBailResult("assigned " + expression.left.name, expression)) {
636
- this.walkExpression(expression.right);
637
- }
638
- this.scope.renames["$" + expression.left.name] = undefined;
639
- if(!this.applyPluginsBailResult("assign " + expression.left.name, expression)) {
640
- this.walkExpression(expression.left);
641
- }
642
- } else {
643
- this.walkExpression(expression.right);
644
- this.scope.renames["$" + expression.left.name] = undefined;
645
- this.walkExpression(expression.left);
646
- }
647
- };
648
-
649
- Parser.prototype.walkConditionalExpression = function walkConditionalExpression(expression) {
650
- var result = this.applyPluginsBailResult("expression ?:", expression);
651
- if(result === undefined) {
652
- this.walkExpression(expression.test);
653
- this.walkExpression(expression.consequent);
654
- if(expression.alternate)
655
- this.walkExpression(expression.alternate);
656
- } else {
657
- if(result)
658
- this.walkExpression(expression.consequent);
659
- else if(expression.alternate)
660
- this.walkExpression(expression.alternate);
661
- }
662
- };
663
-
664
- Parser.prototype.walkNewExpression = function walkNewExpression(expression) {
665
- this.walkExpression(expression.callee);
666
- if(expression.arguments)
667
- this.walkExpressions(expression.arguments);
668
- };
669
-
670
- Parser.prototype.walkYieldExpression = function walkYieldExpression(expression) {
671
- if(expression.argument)
672
- this.walkExpression(expression.argument);
673
- };
674
-
675
- Parser.prototype.walkTemplateLiteral = function walkTemplateLiteral(expression) {
676
- if(expression.expressions)
677
- this.walkExpressions(expression.expressions);
678
- };
679
-
680
- Parser.prototype.walkTaggedTemplateExpression = function walkTaggedTemplateExpression(expression) {
681
- if(expression.tag)
682
- this.walkExpression(expression.tag);
683
- if(expression.quasi && expression.quasi.expressions)
684
- this.walkExpressions(expression.quasi.expressions);
685
- };
686
-
687
- Parser.prototype.walkClassExpression = function walkClassExpression(expression) {
688
- this.walkClass(expression);
689
- };
690
-
691
- Parser.prototype.walkCallExpression = function walkCallExpression(expression) {
692
- function walkIIFE(functionExpression, args) {
693
- var params = functionExpression.params;
694
- var args = args.map(function(arg) {
695
- var renameIdentifier = this.getRenameIdentifier(arg);
696
- if(renameIdentifier && this.applyPluginsBailResult("can-rename " + renameIdentifier, arg)) {
697
- if(!this.applyPluginsBailResult("rename " + renameIdentifier, arg))
698
- return renameIdentifier;
699
- }
700
- this.walkExpression(arg);
701
- }, this);
702
- this.inScope(params.filter(function(identifier, idx) {
703
- return !args[idx];
704
- }), function() {
705
- args.forEach(function(arg, idx) {
706
- if(!arg) return;
707
- if(!params[idx] || params[idx].type !== "Identifier") return;
708
- this.scope.renames["$" + params[idx].name] = arg;
709
- }, this);
710
- if(functionExpression.body.type === "BlockStatement")
711
- this.walkStatement(functionExpression.body);
712
- else
713
- this.walkExpression(functionExpression.body);
714
- }.bind(this));
715
- }
716
- if(expression.callee.type === "MemberExpression" && expression.callee.object.type === "FunctionExpression" && !expression.callee.computed && ["call", "bind"].indexOf(expression.callee.property.name) >= 0 && expression.arguments && expression.arguments.length > 1) {
717
- // (function(...) { }.call/bind(?, ...))
718
- walkIIFE.call(this, expression.callee.object, expression.arguments.slice(1));
719
- this.walkExpression(expression.arguments[0]);
720
- } else if(expression.callee.type === "FunctionExpression" && expression.arguments) {
721
- // (function(...) { }(...))
722
- walkIIFE.call(this, expression.callee, expression.arguments);
723
- } else {
724
-
725
- var callee = this.evaluateExpression(expression.callee);
726
- if(callee.isIdentifier()) {
727
- var result = this.applyPluginsBailResult("call " + callee.identifier, expression);
728
- if(result === true)
729
- return;
730
- }
731
-
732
- if(expression.callee)
733
- this.walkExpression(expression.callee);
734
- if(expression.arguments)
735
- this.walkExpressions(expression.arguments);
736
- }
737
- };
738
-
739
- Parser.prototype.walkMemberExpression = function walkMemberExpression(expression) {
740
- var expr = expression;
741
- var exprName = [];
742
- while(expr.type === "MemberExpression" && !expr.computed) {
743
- exprName.unshift(expr.property.name);
744
- expr = expr.object;
745
- }
746
- if(expr.type === "Identifier" && this.scope.definitions.indexOf(expr.name) === -1) {
747
- exprName.unshift(this.scope.renames["$" + expr.name] || expr.name);
748
- exprName = exprName.join(".");
749
- var result = this.applyPluginsBailResult("expression " + exprName, expression);
750
- if(result === true)
751
- return;
752
- }
753
- this.walkExpression(expression.object);
754
- if(expression.computed === true)
755
- this.walkExpression(expression.property);
756
- };
757
-
758
- Parser.prototype.walkIdentifier = function walkIdentifier(expression) {
759
- if(this.scope.definitions.indexOf(expression.name) === -1) {
760
- var result = this.applyPluginsBailResult("expression " + (this.scope.renames["$" + expression.name] || expression.name), expression);
761
- if(result === true)
762
- return;
763
- }
764
- };
765
-
766
- Parser.prototype.inScope = function inScope(params, fn) {
767
- var oldScope = this.scope;
768
- this.scope = {
769
- inTry: false,
770
- definitions: oldScope.definitions.slice(),
771
- renames: Object.create(oldScope.renames)
772
- };
773
- params.forEach(function(param) {
774
- if(typeof param !== "string") {
775
- if(param.type !== "Identifier")
776
- return;
777
- param = param.name;
778
- }
779
- this.scope.renames["$" + param] = undefined;
780
- this.scope.definitions.push(param);
781
- }, this);
782
- fn();
783
- this.scope = oldScope;
784
- };
785
-
786
- Parser.prototype.evaluateExpression = function evaluateExpression(expression) {
787
- var result = this.applyPluginsBailResult("evaluate " + expression.type, expression);
788
- if(result !== undefined)
789
- return result;
790
- return new BasicEvaluatedExpression().setRange(expression.range);
791
- };
792
-
793
- Parser.prototype.parseString = function parseString(expression) {
794
- switch(expression.type) {
795
- case "BinaryExpression":
796
- if(expression.operator === "+")
797
- return this.parseString(expression.left) + this.parseString(expression.right);
798
- break;
799
- case "Literal":
800
- return expression.value + "";
801
- }
802
- throw new Error(expression.type + " is not supported as parameter for require");
803
- };
804
-
805
- Parser.prototype.parseCalculatedString = function parseCalculatedString(expression) {
806
- switch(expression.type) {
807
- case "BinaryExpression":
808
- if(expression.operator === "+") {
809
- var left = this.parseCalculatedString(expression.left);
810
- var right = this.parseCalculatedString(expression.right);
811
- if(left.code) {
812
- return {
813
- range: left.range,
814
- value: left.value,
815
- code: true
816
- };
817
- } else if(right.code) {
818
- return {
819
- range: [left.range[0], right.range ? right.range[1] : left.range[1]],
820
- value: left.value + right.value,
821
- code: true
822
- };
823
- } else {
824
- return {
825
- range: [left.range[0], right.range[1]],
826
- value: left.value + right.value
827
- };
828
- }
829
- }
830
- break;
831
- case "ConditionalExpression":
832
- var consequent = this.parseCalculatedString(expression.consequent);
833
- var alternate = this.parseCalculatedString(expression.alternate);
834
- var items = [];
835
- if(consequent.conditional)
836
- Array.prototype.push.apply(items, consequent.conditional);
837
- else if(!consequent.code)
838
- items.push(consequent);
839
- else break;
840
- if(alternate.conditional)
841
- Array.prototype.push.apply(items, alternate.conditional);
842
- else if(!alternate.code)
843
- items.push(alternate);
844
- else break;
845
- return {
846
- value: "",
847
- code: true,
848
- conditional: items
849
- };
850
- case "Literal":
851
- return {
852
- range: expression.range,
853
- value: expression.value + ""
854
- };
855
- }
856
- return {
857
- value: "",
858
- code: true
859
- };
860
- };
861
-
862
- ["parseString", "parseCalculatedString"].forEach(function(fn) {
863
- Parser.prototype[fn + "Array"] = function parseXXXArray(expression) {
864
- switch(expression.type) {
865
- case "ArrayExpression":
866
- var arr = [];
867
- if(expression.elements)
868
- expression.elements.forEach(function(expr) {
869
- arr.push(this[fn](expr));
870
- }, this);
871
- return arr;
872
- }
873
- return [this[fn](expression)];
874
- };
875
- });
876
-
877
- var POSSIBLE_AST_OPTIONS = [{
878
- ranges: true,
879
- locations: true,
880
- ecmaVersion: 6,
881
- sourceType: "module"
882
- }, {
883
- ranges: true,
884
- locations: true,
885
- ecmaVersion: 6,
886
- sourceType: "script"
887
- }]
888
-
889
- Parser.prototype.parse = function parse(source, initialState) {
890
- var ast;
891
- for(var i = 0; i < POSSIBLE_AST_OPTIONS.length; i++) {
892
- if(!ast) {
893
- try {
894
- ast = acorn.parse(source, POSSIBLE_AST_OPTIONS[i]);
895
- } catch(e) {
896
- // ignore the error
897
- }
898
- }
899
- }
900
- if(!ast) {
901
- // for the error
902
- ast = acorn.parse(source, {
903
- ranges: true,
904
- locations: true,
905
- ecmaVersion: 6,
906
- sourceType: "module"
907
- });
908
- }
909
- if(!ast || typeof ast !== "object")
910
- throw new Error("Source couldn't be parsed");
911
- var oldScope = this.scope;
912
- var oldState = this.state;
913
- this.scope = {
914
- inTry: false,
915
- definitions: [],
916
- renames: {}
917
- };
918
- var state = this.state = initialState || {};
919
- if(this.applyPluginsBailResult("program", ast) === undefined)
920
- this.walkStatements(ast.body);
921
- this.scope = oldScope;
922
- this.state = oldState;
923
- return state;
924
- };
925
-
926
- Parser.prototype.evaluate = function evaluate(source) {
927
- var ast = acorn.parse("(" + source + ")", {
928
- ranges: true,
929
- locations: true,
930
- ecmaVersion: 6,
931
- sourceType: "module"
932
- });
933
- if(!ast || typeof ast !== "object" || ast.type !== "Program")
934
- throw new Error("evaluate: Source couldn't be parsed");
935
- if(ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement")
936
- throw new Error("evaluate: Source is not a expression");
937
- return this.evaluateExpression(ast.body[0].expression);
938
- };
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ var acorn = require("acorn");
6
+ var Tapable = require("tapable");
7
+ var BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
8
+
9
+ function Parser(options) {
10
+ Tapable.call(this);
11
+ this.options = options;
12
+ this.initializeEvaluating();
13
+ }
14
+ module.exports = Parser;
15
+
16
+ // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
17
+
18
+ Parser.prototype = Object.create(Tapable.prototype);
19
+ Parser.prototype.constructor = Parser;
20
+
21
+ Parser.prototype.initializeEvaluating = function() {
22
+ function joinRanges(startRange, endRange) {
23
+ if(!endRange) return startRange;
24
+ if(!startRange) return endRange;
25
+ return [startRange[0], endRange[1]];
26
+ }
27
+ this.plugin("evaluate Literal", function(expr) {
28
+ switch(typeof expr.value) {
29
+ case "number":
30
+ return new BasicEvaluatedExpression().setNumber(expr.value).setRange(expr.range);
31
+ case "string":
32
+ return new BasicEvaluatedExpression().setString(expr.value).setRange(expr.range);
33
+ case "boolean":
34
+ return new BasicEvaluatedExpression().setBoolean(expr.value).setRange(expr.range);
35
+ }
36
+ if(expr.value === null)
37
+ return new BasicEvaluatedExpression().setNull().setRange(expr.range);
38
+ if(expr.value instanceof RegExp)
39
+ return new BasicEvaluatedExpression().setRegExp(expr.value).setRange(expr.range);
40
+ });
41
+ this.plugin("evaluate LogicalExpression", function(expr) {
42
+ var left;
43
+ var leftAsBool;
44
+ var right;
45
+ if(expr.operator === "&&") {
46
+ left = this.evaluateExpression(expr.left);
47
+ leftAsBool = left && left.asBool();
48
+ if(leftAsBool === false) return left.setRange(expr.range);
49
+ if(leftAsBool !== true) return;
50
+ right = this.evaluateExpression(expr.right);
51
+ return right.setRange(expr.range);
52
+ } else if(expr.operator === "||") {
53
+ left = this.evaluateExpression(expr.left);
54
+ leftAsBool = left && left.asBool();
55
+ if(leftAsBool === true) return left.setRange(expr.range);
56
+ if(leftAsBool !== false) return;
57
+ right = this.evaluateExpression(expr.right);
58
+ return right.setRange(expr.range);
59
+ }
60
+ });
61
+ this.plugin("evaluate BinaryExpression", function(expr) {
62
+ var left;
63
+ var right;
64
+ var res;
65
+ if(expr.operator === "+") {
66
+ left = this.evaluateExpression(expr.left);
67
+ right = this.evaluateExpression(expr.right);
68
+ if(!left || !right) return;
69
+ res = new BasicEvaluatedExpression();
70
+ if(left.isString()) {
71
+ if(right.isString()) {
72
+ res.setString(left.string + right.string);
73
+ } else if(right.isNumber()) {
74
+ res.setString(left.string + right.number);
75
+ } else if(right.isWrapped() && right.prefix && right.prefix.isString()) {
76
+ res.setWrapped(
77
+ new BasicEvaluatedExpression()
78
+ .setString(left.string + right.prefix.string)
79
+ .setRange(joinRanges(left.range, right.prefix.range)),
80
+ right.postfix);
81
+ } else {
82
+ res.setWrapped(left, null);
83
+ }
84
+ } else if(left.isNumber()) {
85
+ if(right.isString()) {
86
+ res.setString(left.number + right.string);
87
+ } else if(right.isNumber()) {
88
+ res.setNumber(left.number + right.number);
89
+ }
90
+ } else if(left.isWrapped()) {
91
+ if(left.postfix && left.postfix.isString() && right.isString()) {
92
+ res.setWrapped(left.prefix,
93
+ new BasicEvaluatedExpression()
94
+ .setString(left.postfix.string + right.string)
95
+ .setRange(joinRanges(left.postfix.range, right.range))
96
+ );
97
+ } else if(left.postfix && left.postfix.isString() && right.isNumber()) {
98
+ res.setWrapped(left.prefix,
99
+ new BasicEvaluatedExpression()
100
+ .setString(left.postfix.string + right.number)
101
+ .setRange(joinRanges(left.postfix.range, right.range))
102
+ );
103
+ } else if(right.isString()) {
104
+ res.setWrapped(left.prefix, right);
105
+ } else if(right.isNumber()) {
106
+ res.setWrapped(left.prefix,
107
+ new BasicEvaluatedExpression()
108
+ .setString(right.number + "")
109
+ .setRange(right.range));
110
+ } else {
111
+ res.setWrapped(left.prefix, new BasicEvaluatedExpression());
112
+ }
113
+ } else {
114
+ if(right.isString()) {
115
+ res.setWrapped(null, right);
116
+ }
117
+ }
118
+ res.setRange(expr.range);
119
+ return res;
120
+ } else if(expr.operator === "-") {
121
+ left = this.evaluateExpression(expr.left);
122
+ right = this.evaluateExpression(expr.right);
123
+ if(!left || !right) return;
124
+ if(!left.isNumber() || !right.isNumber()) return;
125
+ res = new BasicEvaluatedExpression();
126
+ res.setNumber(left.number - right.number);
127
+ res.setRange(expr.range);
128
+ return res;
129
+ } else if(expr.operator === "*") {
130
+ left = this.evaluateExpression(expr.left);
131
+ right = this.evaluateExpression(expr.right);
132
+ if(!left || !right) return;
133
+ if(!left.isNumber() || !right.isNumber()) return;
134
+ res = new BasicEvaluatedExpression();
135
+ res.setNumber(left.number * right.number);
136
+ res.setRange(expr.range);
137
+ return res;
138
+ } else if(expr.operator === "/") {
139
+ left = this.evaluateExpression(expr.left);
140
+ right = this.evaluateExpression(expr.right);
141
+ if(!left || !right) return;
142
+ if(!left.isNumber() || !right.isNumber()) return;
143
+ res = new BasicEvaluatedExpression();
144
+ res.setNumber(left.number / right.number);
145
+ res.setRange(expr.range);
146
+ return res;
147
+ } else if(expr.operator === "==" || expr.operator === "===") {
148
+ left = this.evaluateExpression(expr.left);
149
+ right = this.evaluateExpression(expr.right);
150
+ if(!left || !right) return;
151
+ res = new BasicEvaluatedExpression();
152
+ res.setRange(expr.range);
153
+ if(left.isString() && right.isString()) {
154
+ return res.setBoolean(left.string === right.string);
155
+ } else if(left.isNumber() && right.isNumber()) {
156
+ return res.setBoolean(left.number === right.number);
157
+ } else if(left.isBoolean() && right.isBoolean()) {
158
+ return res.setBoolean(left.bool === right.bool);
159
+ }
160
+ } else if(expr.operator === "!=" || expr.operator === "!==") {
161
+ left = this.evaluateExpression(expr.left);
162
+ right = this.evaluateExpression(expr.right);
163
+ if(!left || !right) return;
164
+ res = new BasicEvaluatedExpression();
165
+ res.setRange(expr.range);
166
+ if(left.isString() && right.isString()) {
167
+ return res.setBoolean(left.string !== right.string);
168
+ } else if(left.isNumber() && right.isNumber()) {
169
+ return res.setBoolean(left.number !== right.number);
170
+ } else if(left.isBoolean() && right.isBoolean()) {
171
+ return res.setBoolean(left.bool !== right.bool);
172
+ }
173
+ }
174
+ });
175
+ this.plugin("evaluate UnaryExpression", function(expr) {
176
+ if(expr.operator === "typeof") {
177
+ var res;
178
+ if(expr.argument.type === "Identifier") {
179
+ var name = this.scope.renames["$" + expr.argument.name] || expr.argument.name;
180
+ if(this.scope.definitions.indexOf(name) === -1) {
181
+ res = this.applyPluginsBailResult("evaluate typeof " + name, expr);
182
+ if(res !== undefined) return res;
183
+ }
184
+ }
185
+ if(expr.argument.type === "MemberExpression") {
186
+ var expression = expr.argument;
187
+ var exprName = [];
188
+ while(expression.type === "MemberExpression" && !expression.computed) {
189
+ exprName.unshift(this.scope.renames["$" + expression.property.name] || expression.property.name);
190
+ expression = expression.object;
191
+ }
192
+ if(expression.type === "Identifier") {
193
+ exprName.unshift(this.scope.renames["$" + expression.name] || expression.name);
194
+ if(this.scope.definitions.indexOf(name) === -1) {
195
+ exprName = exprName.join(".");
196
+ res = this.applyPluginsBailResult("evaluate typeof " + exprName, expr);
197
+ if(res !== undefined) return res;
198
+ }
199
+ }
200
+ }
201
+ if(expr.argument.type === "FunctionExpression") {
202
+ return new BasicEvaluatedExpression().setString("function").setRange(expr.range);
203
+ }
204
+ var arg = this.evaluateExpression(expr.argument);
205
+ if(arg.isString() || arg.isWrapped()) return new BasicEvaluatedExpression().setString("string").setRange(expr.range);
206
+ else if(arg.isNumber()) return new BasicEvaluatedExpression().setString("number").setRange(expr.range);
207
+ else if(arg.isBoolean()) return new BasicEvaluatedExpression().setString("boolean").setRange(expr.range);
208
+ else if(arg.isArray() || arg.isConstArray() || arg.isRegExp()) return new BasicEvaluatedExpression().setString("object").setRange(expr.range);
209
+ } else if(expr.operator === "!") {
210
+ var argument = this.evaluateExpression(expr.argument);
211
+ if(!argument) return;
212
+ if(argument.isBoolean()) {
213
+ return new BasicEvaluatedExpression().setBoolean(!argument.bool).setRange(expr.range);
214
+ } else if(argument.isString()) {
215
+ return new BasicEvaluatedExpression().setBoolean(!argument.string).setRange(expr.range);
216
+ } else if(argument.isNumber()) {
217
+ return new BasicEvaluatedExpression().setBoolean(!argument.number).setRange(expr.range);
218
+ }
219
+ }
220
+ });
221
+ this.plugin("evaluate typeof undefined", function(expr) {
222
+ return new BasicEvaluatedExpression().setString("undefined").setRange(expr.range);
223
+ });
224
+ this.plugin("evaluate Identifier", function(expr) {
225
+ var name = this.scope.renames["$" + expr.name] || expr.name;
226
+ if(this.scope.definitions.indexOf(expr.name) === -1) {
227
+ var result = this.applyPluginsBailResult("evaluate Identifier " + name, expr);
228
+ if(result) return result;
229
+ return new BasicEvaluatedExpression().setIdentifier(name).setRange(expr.range);
230
+ } else {
231
+ return this.applyPluginsBailResult("evaluate defined Identifier " + name, expr);
232
+ }
233
+ });
234
+ this.plugin("evaluate MemberExpression", function(expression) {
235
+ var expr = expression;
236
+ var exprName = [];
237
+ while(expr.type === "MemberExpression" && !expr.computed) {
238
+ exprName.unshift(expr.property.name);
239
+ expr = expr.object;
240
+ }
241
+ if(expr.type === "Identifier") {
242
+ var name = this.scope.renames["$" + expr.name] || expr.name;
243
+ if(this.scope.definitions.indexOf(name) === -1) {
244
+ exprName.unshift(name);
245
+ exprName = exprName.join(".");
246
+ if(this.scope.definitions.indexOf(expr.name) === -1) {
247
+ var result = this.applyPluginsBailResult("evaluate Identifier " + exprName, expression);
248
+ if(result) return result;
249
+ return new BasicEvaluatedExpression().setIdentifier(exprName).setRange(expression.range);
250
+ } else {
251
+ return this.applyPluginsBailResult("evaluate defined Identifier " + exprName, expression);
252
+ }
253
+ }
254
+ }
255
+ });
256
+ this.plugin("evaluate CallExpression", function(expr) {
257
+ if(expr.callee.type !== "MemberExpression") return;
258
+ if(expr.callee.computed) return;
259
+ var param = this.evaluateExpression(expr.callee.object);
260
+ if(!param) return;
261
+ return this.applyPluginsBailResult("evaluate CallExpression ." + expr.callee.property.name, expr, param);
262
+ });
263
+ this.plugin("evaluate CallExpression .replace", function(expr, param) {
264
+ if(!param.isString()) return;
265
+ if(expr.arguments.length !== 2) return;
266
+ var arg1 = this.evaluateExpression(expr.arguments[0]);
267
+ var arg2 = this.evaluateExpression(expr.arguments[1]);
268
+ if(!arg1.isString() && !arg1.isRegExp()) return;
269
+ arg1 = arg1.regExp || arg1.string;
270
+ if(!arg2.isString()) return;
271
+ arg2 = arg2.string;
272
+ return new BasicEvaluatedExpression().setString(param.string.replace(arg1, arg2)).setRange(expr.range);
273
+ });
274
+ ["substr", "substring"].forEach(function(fn) {
275
+ this.plugin("evaluate CallExpression ." + fn, function(expr, param) {
276
+ if(!param.isString()) return;
277
+ var arg1;
278
+ var result, str = param.string;
279
+ switch(expr.arguments.length) {
280
+ case 1:
281
+ arg1 = this.evaluateExpression(expr.arguments[0]);
282
+ if(!arg1.isNumber()) return;
283
+ result = str[fn](arg1.number);
284
+ break;
285
+ case 2:
286
+ arg1 = this.evaluateExpression(expr.arguments[0]);
287
+ var arg2 = this.evaluateExpression(expr.arguments[1]);
288
+ if(!arg1.isNumber()) return;
289
+ if(!arg2.isNumber()) return;
290
+ result = str[fn](arg1.number, arg2.number);
291
+ break;
292
+ default:
293
+ return;
294
+ }
295
+ return new BasicEvaluatedExpression().setString(result).setRange(expr.range);
296
+ });
297
+ }, this);
298
+ this.plugin("evaluate CallExpression .split", function(expr, param) {
299
+ if(!param.isString()) return;
300
+ if(expr.arguments.length !== 1) return;
301
+ var result;
302
+ var arg = this.evaluateExpression(expr.arguments[0]);
303
+ if(arg.isString()) {
304
+ result = param.string.split(arg.string);
305
+ } else if(arg.isRegExp()) {
306
+ result = param.string.split(arg.regExp);
307
+ } else return;
308
+ return new BasicEvaluatedExpression().setArray(result).setRange(expr.range);
309
+ });
310
+ this.plugin("evaluate ConditionalExpression", function(expr) {
311
+ var condition = this.evaluateExpression(expr.test);
312
+ var conditionValue = condition.asBool();
313
+ var res;
314
+ if(conditionValue === undefined) {
315
+ var consequent = this.evaluateExpression(expr.consequent);
316
+ var alternate = this.evaluateExpression(expr.alternate);
317
+ if(!consequent || !alternate) return;
318
+ res = new BasicEvaluatedExpression();
319
+ if(consequent.isConditional())
320
+ res.setOptions(consequent.options);
321
+ else
322
+ res.setOptions([consequent]);
323
+ if(alternate.isConditional())
324
+ res.addOptions(alternate.options);
325
+ else
326
+ res.addOptions([alternate]);
327
+ } else {
328
+ res = this.evaluateExpression(conditionValue ? expr.consequent : expr.alternate);
329
+ }
330
+ res.setRange(expr.range);
331
+ return res;
332
+ });
333
+ this.plugin("evaluate ArrayExpression", function(expr) {
334
+ var items = expr.elements.map(function(element) {
335
+ return element !== null && this.evaluateExpression(element);
336
+ }, this);
337
+ if(items.filter(function(i) {
338
+ return !i;
339
+ }).length > 0) return;
340
+ return new BasicEvaluatedExpression().setItems(items).setRange(expr.range);
341
+ });
342
+ };
343
+
344
+ Parser.prototype.getRenameIdentifier = function getRenameIdentifier(expr) {
345
+ var result = this.evaluateExpression(expr);
346
+ if(!result) return;
347
+ if(result.isIdentifier()) return result.identifier;
348
+ return;
349
+ };
350
+
351
+ Parser.prototype.walkClass = function walkClass(classy) {
352
+ if(classy.superClass)
353
+ this.walkExpression(classy.superClass);
354
+ if(classy.body && classy.body.type === "ClassBody") {
355
+ classy.body.body.forEach(function(methodDefinition) {
356
+ if(methodDefinition.type === "MethodDefinition")
357
+ this.walkMethodDefinition(methodDefinition);
358
+ }, this);
359
+ }
360
+ };
361
+
362
+ Parser.prototype.walkMethodDefinition = function walkMethodDefinition(methodDefinition) {
363
+ if(methodDefinition.computed && methodDefinition.key)
364
+ this.walkExpression(methodDefinition.key);
365
+ if(methodDefinition.value)
366
+ this.walkExpression(methodDefinition.value);
367
+ };
368
+
369
+ Parser.prototype.walkStatements = function walkStatements(statements) {
370
+ statements.forEach(function(statement) {
371
+ this.walkStatement(statement);
372
+ }, this);
373
+ };
374
+
375
+ Parser.prototype.walkStatement = function walkStatement(statement) {
376
+ if(this.applyPluginsBailResult("statement", statement) !== undefined) return;
377
+ if(this["walk" + statement.type])
378
+ this["walk" + statement.type](statement);
379
+ };
380
+
381
+ // Real Statements
382
+ Parser.prototype.walkBlockStatement = function walkBlockStatement(statement) {
383
+ this.walkStatements(statement.body);
384
+ };
385
+
386
+ Parser.prototype.walkExpressionStatement = function walkExpressionStatement(statement) {
387
+ this.walkExpression(statement.expression);
388
+ };
389
+
390
+ Parser.prototype.walkIfStatement = function walkIfStatement(statement) {
391
+ var result = this.applyPluginsBailResult("statement if", statement);
392
+ if(result === undefined) {
393
+ this.walkExpression(statement.test);
394
+ this.walkStatement(statement.consequent);
395
+ if(statement.alternate)
396
+ this.walkStatement(statement.alternate);
397
+ } else {
398
+ if(result)
399
+ this.walkStatement(statement.consequent);
400
+ else if(statement.alternate)
401
+ this.walkStatement(statement.alternate);
402
+ }
403
+ };
404
+
405
+ Parser.prototype.walkLabeledStatement = function walkLabeledStatement(statement) {
406
+ var result = this.applyPluginsBailResult("label " + statement.label.name, statement);
407
+ if(result !== true)
408
+ this.walkStatement(statement.body);
409
+ };
410
+
411
+ Parser.prototype.walkWithStatement = function walkWithStatement(statement) {
412
+ this.walkExpression(statement.object);
413
+ this.walkStatement(statement.body);
414
+ };
415
+
416
+ Parser.prototype.walkSwitchStatement = function walkSwitchStatement(statement) {
417
+ this.walkExpression(statement.discriminant);
418
+ this.walkSwitchCases(statement.cases);
419
+ };
420
+
421
+ Parser.prototype.walkReturnStatement =
422
+ Parser.prototype.walkThrowStatement = function walkArgumentStatement(statement) {
423
+ if(statement.argument)
424
+ this.walkExpression(statement.argument);
425
+ };
426
+
427
+ Parser.prototype.walkTryStatement = function walkTryStatement(statement) {
428
+ if(this.scope.inTry) {
429
+ this.walkStatement(statement.block);
430
+ } else {
431
+ this.scope.inTry = true;
432
+ this.walkStatement(statement.block);
433
+ this.scope.inTry = false;
434
+ }
435
+ if(statement.handler)
436
+ this.walkCatchClause(statement.handler);
437
+ if(statement.finalizer)
438
+ this.walkStatement(statement.finalizer);
439
+ };
440
+
441
+ Parser.prototype.walkWhileStatement =
442
+ Parser.prototype.walkDoWhileStatement = function walkLoopStatement(statement) {
443
+ this.walkExpression(statement.test);
444
+ this.walkStatement(statement.body);
445
+ };
446
+
447
+ Parser.prototype.walkForStatement = function walkForStatement(statement) {
448
+ if(statement.init) {
449
+ if(statement.init.type === "VariableDeclaration")
450
+ this.walkStatement(statement.init);
451
+ else
452
+ this.walkExpression(statement.init);
453
+ }
454
+ if(statement.test)
455
+ this.walkExpression(statement.test);
456
+ if(statement.update)
457
+ this.walkExpression(statement.update);
458
+ this.walkStatement(statement.body);
459
+ };
460
+
461
+ Parser.prototype.walkForInStatement = function walkForInStatement(statement) {
462
+ if(statement.left.type === "VariableDeclaration")
463
+ this.walkStatement(statement.left);
464
+ else
465
+ this.walkExpression(statement.left);
466
+ this.walkExpression(statement.right);
467
+ this.walkStatement(statement.body);
468
+ };
469
+
470
+ Parser.prototype.walkForOfStatement = function walkForOfStatement(statement) {
471
+ if(statement.left.type === "VariableDeclaration")
472
+ this.walkStatement(statement.left);
473
+ else
474
+ this.walkExpression(statement.left);
475
+ this.walkExpression(statement.right);
476
+ this.walkStatement(statement.body);
477
+ };
478
+
479
+ // Declarations
480
+ Parser.prototype.walkFunctionDeclaration = function walkFunctionDeclaration(statement) {
481
+ this.scope.renames["$" + statement.id.name] = undefined;
482
+ this.scope.definitions.push(statement.id.name);
483
+ this.inScope(statement.params, function() {
484
+ if(statement.body.type === "BlockStatement")
485
+ this.walkStatement(statement.body);
486
+ else
487
+ this.walkExpression(statement.body);
488
+ }.bind(this));
489
+ };
490
+
491
+ Parser.prototype.walkVariableDeclaration = function walkVariableDeclaration(statement) {
492
+ if(statement.declarations)
493
+ this.walkVariableDeclarators(statement.declarations);
494
+ };
495
+
496
+ Parser.prototype.walkClassDeclaration = function walkClassDeclaration(statement) {
497
+ this.walkClass(statement);
498
+ };
499
+
500
+ Parser.prototype.walkSwitchCases = function walkSwitchCases(switchCases) {
501
+ switchCases.forEach(function(switchCase) {
502
+ if(switchCase.test)
503
+ this.walkExpression(switchCase.test);
504
+ this.walkStatements(switchCase.consequent);
505
+ }, this);
506
+ };
507
+
508
+ Parser.prototype.walkCatchClause = function walkCatchClause(catchClause) {
509
+ if(catchClause.guard)
510
+ this.walkExpression(catchClause.guard);
511
+ this.inScope([catchClause.param], function() {
512
+ this.walkStatement(catchClause.body);
513
+ }.bind(this));
514
+ };
515
+
516
+ Parser.prototype.walkVariableDeclarators = function walkVariableDeclarators(declarators) {
517
+ declarators.forEach(function(declarator) {
518
+ switch(declarator.type) {
519
+ case "VariableDeclarator":
520
+ var renameIdentifier = declarator.init && this.getRenameIdentifier(declarator.init);
521
+ if(renameIdentifier && declarator.id.type === "Identifier" && this.applyPluginsBailResult("can-rename " + renameIdentifier, declarator.init)) {
522
+ // renaming with "var a = b;"
523
+ if(!this.applyPluginsBailResult("rename " + renameIdentifier, declarator.init)) {
524
+ this.scope.renames["$" + declarator.id.name] = this.scope.renames["$" + renameIdentifier] || renameIdentifier;
525
+ var idx = this.scope.definitions.indexOf(declarator.id.name);
526
+ if(idx >= 0) this.scope.definitions.splice(idx, 1);
527
+ }
528
+ } else if(declarator.id.type === "Identifier" && !this.applyPluginsBailResult("var " + declarator.id.name, declarator)) {
529
+ this.scope.renames["$" + declarator.id.name] = undefined;
530
+ this.scope.definitions.push(declarator.id.name);
531
+ if(declarator.init)
532
+ this.walkExpression(declarator.init);
533
+ } else {
534
+ this.walkExpression(declarator.id);
535
+ if(declarator.init)
536
+ this.walkExpression(declarator.init);
537
+ }
538
+ break;
539
+ }
540
+ }, this);
541
+ };
542
+
543
+ Parser.prototype.walkExpressions = function walkExpressions(expressions) {
544
+ expressions.forEach(function(expression) {
545
+ if(expression)
546
+ this.walkExpression(expression);
547
+ }, this);
548
+ };
549
+
550
+ Parser.prototype.walkExpression = function walkExpression(expression) {
551
+ if(this["walk" + expression.type])
552
+ return this["walk" + expression.type](expression);
553
+ };
554
+
555
+ Parser.prototype.walkArrayExpression = function walkArrayExpression(expression) {
556
+ if(expression.elements)
557
+ this.walkExpressions(expression.elements);
558
+ };
559
+
560
+ Parser.prototype.walkSpreadElement = function walkSpreadElement(expression) {
561
+ if(expression.argument)
562
+ this.walkExpression(expression.argument);
563
+ };
564
+
565
+ Parser.prototype.walkObjectExpression = function walkObjectExpression(expression) {
566
+ expression.properties.forEach(function(prop) {
567
+ if(prop.computed)
568
+ this.walkExpression(prop.key)
569
+ this.walkExpression(prop.value);
570
+ }, this);
571
+ };
572
+
573
+ Parser.prototype.walkFunctionExpression = function walkFunctionExpression(expression) {
574
+ this.inScope(expression.params, function() {
575
+ if(expression.body.type === "BlockStatement")
576
+ this.walkStatement(expression.body);
577
+ else
578
+ this.walkExpression(expression.body);
579
+ }.bind(this));
580
+ };
581
+
582
+ Parser.prototype.walkArrowFunctionExpression = function walkArrowFunctionExpression(expression) {
583
+ this.inScope(expression.params, function() {
584
+ if(expression.body.type === "BlockStatement")
585
+ this.walkStatement(expression.body);
586
+ else
587
+ this.walkExpression(expression.body);
588
+ }.bind(this));
589
+ };
590
+
591
+ Parser.prototype.walkSequenceExpression = function walkSequenceExpression(expression) {
592
+ if(expression.expressions)
593
+ this.walkExpressions(expression.expressions);
594
+ };
595
+
596
+ Parser.prototype.walkUpdateExpression = function walkUpdateExpression(expression) {
597
+ this.walkExpression(expression.argument);
598
+ };
599
+
600
+ Parser.prototype.walkUnaryExpression = function walkUnaryExpression(expression) {
601
+ if(expression.operator === "typeof") {
602
+ var expr = expression.argument;
603
+ var exprName = [];
604
+ while(expr.type === "MemberExpression" && !expr.computed) {
605
+ exprName.unshift(expr.property.name);
606
+ expr = expr.object;
607
+ }
608
+ if(expr.type === "Identifier" && this.scope.definitions.indexOf(expr.name) === -1) {
609
+ exprName.unshift(this.scope.renames["$" + expr.name] || expr.name);
610
+ exprName = exprName.join(".");
611
+ var result = this.applyPluginsBailResult("typeof " + exprName, expression);
612
+ if(result === true)
613
+ return;
614
+ }
615
+ }
616
+ this.walkExpression(expression.argument);
617
+ };
618
+
619
+ Parser.prototype.walkBinaryExpression =
620
+ Parser.prototype.walkLogicalExpression = function walkLeftRightExpression(expression) {
621
+ this.walkExpression(expression.left);
622
+ this.walkExpression(expression.right);
623
+ };
624
+
625
+ Parser.prototype.walkAssignmentExpression = function walkAssignmentExpression(expression) {
626
+ var renameIdentifier = this.getRenameIdentifier(expression.right);
627
+ if(expression.left.type === "Identifier" && renameIdentifier && this.applyPluginsBailResult("can-rename " + renameIdentifier, expression.right)) {
628
+ // renaming "a = b;"
629
+ if(!this.applyPluginsBailResult("rename " + renameIdentifier, expression.right)) {
630
+ this.scope.renames["$" + expression.left.name] = renameIdentifier;
631
+ var idx = this.scope.definitions.indexOf(expression.left.name);
632
+ if(idx >= 0) this.scope.definitions.splice(idx, 1);
633
+ }
634
+ } else if(expression.left.type === "Identifier") {
635
+ if(!this.applyPluginsBailResult("assigned " + expression.left.name, expression)) {
636
+ this.walkExpression(expression.right);
637
+ }
638
+ this.scope.renames["$" + expression.left.name] = undefined;
639
+ if(!this.applyPluginsBailResult("assign " + expression.left.name, expression)) {
640
+ this.walkExpression(expression.left);
641
+ }
642
+ } else {
643
+ this.walkExpression(expression.right);
644
+ this.scope.renames["$" + expression.left.name] = undefined;
645
+ this.walkExpression(expression.left);
646
+ }
647
+ };
648
+
649
+ Parser.prototype.walkConditionalExpression = function walkConditionalExpression(expression) {
650
+ var result = this.applyPluginsBailResult("expression ?:", expression);
651
+ if(result === undefined) {
652
+ this.walkExpression(expression.test);
653
+ this.walkExpression(expression.consequent);
654
+ if(expression.alternate)
655
+ this.walkExpression(expression.alternate);
656
+ } else {
657
+ if(result)
658
+ this.walkExpression(expression.consequent);
659
+ else if(expression.alternate)
660
+ this.walkExpression(expression.alternate);
661
+ }
662
+ };
663
+
664
+ Parser.prototype.walkNewExpression = function walkNewExpression(expression) {
665
+ this.walkExpression(expression.callee);
666
+ if(expression.arguments)
667
+ this.walkExpressions(expression.arguments);
668
+ };
669
+
670
+ Parser.prototype.walkYieldExpression = function walkYieldExpression(expression) {
671
+ if(expression.argument)
672
+ this.walkExpression(expression.argument);
673
+ };
674
+
675
+ Parser.prototype.walkTemplateLiteral = function walkTemplateLiteral(expression) {
676
+ if(expression.expressions)
677
+ this.walkExpressions(expression.expressions);
678
+ };
679
+
680
+ Parser.prototype.walkTaggedTemplateExpression = function walkTaggedTemplateExpression(expression) {
681
+ if(expression.tag)
682
+ this.walkExpression(expression.tag);
683
+ if(expression.quasi && expression.quasi.expressions)
684
+ this.walkExpressions(expression.quasi.expressions);
685
+ };
686
+
687
+ Parser.prototype.walkClassExpression = function walkClassExpression(expression) {
688
+ this.walkClass(expression);
689
+ };
690
+
691
+ Parser.prototype.walkCallExpression = function walkCallExpression(expression) {
692
+ function walkIIFE(functionExpression, args) {
693
+ var params = functionExpression.params;
694
+ var args = args.map(function(arg) {
695
+ var renameIdentifier = this.getRenameIdentifier(arg);
696
+ if(renameIdentifier && this.applyPluginsBailResult("can-rename " + renameIdentifier, arg)) {
697
+ if(!this.applyPluginsBailResult("rename " + renameIdentifier, arg))
698
+ return renameIdentifier;
699
+ }
700
+ this.walkExpression(arg);
701
+ }, this);
702
+ this.inScope(params.filter(function(identifier, idx) {
703
+ return !args[idx];
704
+ }), function() {
705
+ args.forEach(function(arg, idx) {
706
+ if(!arg) return;
707
+ if(!params[idx] || params[idx].type !== "Identifier") return;
708
+ this.scope.renames["$" + params[idx].name] = arg;
709
+ }, this);
710
+ if(functionExpression.body.type === "BlockStatement")
711
+ this.walkStatement(functionExpression.body);
712
+ else
713
+ this.walkExpression(functionExpression.body);
714
+ }.bind(this));
715
+ }
716
+ if(expression.callee.type === "MemberExpression" && expression.callee.object.type === "FunctionExpression" && !expression.callee.computed && ["call", "bind"].indexOf(expression.callee.property.name) >= 0 && expression.arguments && expression.arguments.length > 1) {
717
+ // (function(...) { }.call/bind(?, ...))
718
+ walkIIFE.call(this, expression.callee.object, expression.arguments.slice(1));
719
+ this.walkExpression(expression.arguments[0]);
720
+ } else if(expression.callee.type === "FunctionExpression" && expression.arguments) {
721
+ // (function(...) { }(...))
722
+ walkIIFE.call(this, expression.callee, expression.arguments);
723
+ } else {
724
+
725
+ var callee = this.evaluateExpression(expression.callee);
726
+ if(callee.isIdentifier()) {
727
+ var result = this.applyPluginsBailResult("call " + callee.identifier, expression);
728
+ if(result === true)
729
+ return;
730
+ }
731
+
732
+ if(expression.callee)
733
+ this.walkExpression(expression.callee);
734
+ if(expression.arguments)
735
+ this.walkExpressions(expression.arguments);
736
+ }
737
+ };
738
+
739
+ Parser.prototype.walkMemberExpression = function walkMemberExpression(expression) {
740
+ var expr = expression;
741
+ var exprName = [];
742
+ while(expr.type === "MemberExpression" && !expr.computed) {
743
+ exprName.unshift(expr.property.name);
744
+ expr = expr.object;
745
+ }
746
+ if(expr.type === "Identifier" && this.scope.definitions.indexOf(expr.name) === -1) {
747
+ exprName.unshift(this.scope.renames["$" + expr.name] || expr.name);
748
+ exprName = exprName.join(".");
749
+ var result = this.applyPluginsBailResult("expression " + exprName, expression);
750
+ if(result === true)
751
+ return;
752
+ }
753
+ this.walkExpression(expression.object);
754
+ if(expression.computed === true)
755
+ this.walkExpression(expression.property);
756
+ };
757
+
758
+ Parser.prototype.walkIdentifier = function walkIdentifier(expression) {
759
+ if(this.scope.definitions.indexOf(expression.name) === -1) {
760
+ var result = this.applyPluginsBailResult("expression " + (this.scope.renames["$" + expression.name] || expression.name), expression);
761
+ if(result === true)
762
+ return;
763
+ }
764
+ };
765
+
766
+ Parser.prototype.inScope = function inScope(params, fn) {
767
+ var oldScope = this.scope;
768
+ this.scope = {
769
+ inTry: false,
770
+ definitions: oldScope.definitions.slice(),
771
+ renames: Object.create(oldScope.renames)
772
+ };
773
+ params.forEach(function(param) {
774
+ if(typeof param !== "string") {
775
+ if(param.type !== "Identifier")
776
+ return;
777
+ param = param.name;
778
+ }
779
+ this.scope.renames["$" + param] = undefined;
780
+ this.scope.definitions.push(param);
781
+ }, this);
782
+ fn();
783
+ this.scope = oldScope;
784
+ };
785
+
786
+ Parser.prototype.evaluateExpression = function evaluateExpression(expression) {
787
+ var result = this.applyPluginsBailResult("evaluate " + expression.type, expression);
788
+ if(result !== undefined)
789
+ return result;
790
+ return new BasicEvaluatedExpression().setRange(expression.range);
791
+ };
792
+
793
+ Parser.prototype.parseString = function parseString(expression) {
794
+ switch(expression.type) {
795
+ case "BinaryExpression":
796
+ if(expression.operator === "+")
797
+ return this.parseString(expression.left) + this.parseString(expression.right);
798
+ break;
799
+ case "Literal":
800
+ return expression.value + "";
801
+ }
802
+ throw new Error(expression.type + " is not supported as parameter for require");
803
+ };
804
+
805
+ Parser.prototype.parseCalculatedString = function parseCalculatedString(expression) {
806
+ switch(expression.type) {
807
+ case "BinaryExpression":
808
+ if(expression.operator === "+") {
809
+ var left = this.parseCalculatedString(expression.left);
810
+ var right = this.parseCalculatedString(expression.right);
811
+ if(left.code) {
812
+ return {
813
+ range: left.range,
814
+ value: left.value,
815
+ code: true
816
+ };
817
+ } else if(right.code) {
818
+ return {
819
+ range: [left.range[0], right.range ? right.range[1] : left.range[1]],
820
+ value: left.value + right.value,
821
+ code: true
822
+ };
823
+ } else {
824
+ return {
825
+ range: [left.range[0], right.range[1]],
826
+ value: left.value + right.value
827
+ };
828
+ }
829
+ }
830
+ break;
831
+ case "ConditionalExpression":
832
+ var consequent = this.parseCalculatedString(expression.consequent);
833
+ var alternate = this.parseCalculatedString(expression.alternate);
834
+ var items = [];
835
+ if(consequent.conditional)
836
+ Array.prototype.push.apply(items, consequent.conditional);
837
+ else if(!consequent.code)
838
+ items.push(consequent);
839
+ else break;
840
+ if(alternate.conditional)
841
+ Array.prototype.push.apply(items, alternate.conditional);
842
+ else if(!alternate.code)
843
+ items.push(alternate);
844
+ else break;
845
+ return {
846
+ value: "",
847
+ code: true,
848
+ conditional: items
849
+ };
850
+ case "Literal":
851
+ return {
852
+ range: expression.range,
853
+ value: expression.value + ""
854
+ };
855
+ }
856
+ return {
857
+ value: "",
858
+ code: true
859
+ };
860
+ };
861
+
862
+ ["parseString", "parseCalculatedString"].forEach(function(fn) {
863
+ Parser.prototype[fn + "Array"] = function parseXXXArray(expression) {
864
+ switch(expression.type) {
865
+ case "ArrayExpression":
866
+ var arr = [];
867
+ if(expression.elements)
868
+ expression.elements.forEach(function(expr) {
869
+ arr.push(this[fn](expr));
870
+ }, this);
871
+ return arr;
872
+ }
873
+ return [this[fn](expression)];
874
+ };
875
+ });
876
+
877
+ var POSSIBLE_AST_OPTIONS = [{
878
+ ranges: true,
879
+ locations: true,
880
+ ecmaVersion: 6,
881
+ sourceType: "module"
882
+ }, {
883
+ ranges: true,
884
+ locations: true,
885
+ ecmaVersion: 6,
886
+ sourceType: "script"
887
+ }]
888
+
889
+ Parser.prototype.parse = function parse(source, initialState) {
890
+ var ast;
891
+ for(var i = 0; i < POSSIBLE_AST_OPTIONS.length; i++) {
892
+ if(!ast) {
893
+ try {
894
+ ast = acorn.parse(source, POSSIBLE_AST_OPTIONS[i]);
895
+ } catch(e) {
896
+ // ignore the error
897
+ }
898
+ }
899
+ }
900
+ if(!ast) {
901
+ // for the error
902
+ ast = acorn.parse(source, {
903
+ ranges: true,
904
+ locations: true,
905
+ ecmaVersion: 6,
906
+ sourceType: "module"
907
+ });
908
+ }
909
+ if(!ast || typeof ast !== "object")
910
+ throw new Error("Source couldn't be parsed");
911
+ var oldScope = this.scope;
912
+ var oldState = this.state;
913
+ this.scope = {
914
+ inTry: false,
915
+ definitions: [],
916
+ renames: {}
917
+ };
918
+ var state = this.state = initialState || {};
919
+ if(this.applyPluginsBailResult("program", ast) === undefined)
920
+ this.walkStatements(ast.body);
921
+ this.scope = oldScope;
922
+ this.state = oldState;
923
+ return state;
924
+ };
925
+
926
+ Parser.prototype.evaluate = function evaluate(source) {
927
+ var ast = acorn.parse("(" + source + ")", {
928
+ ranges: true,
929
+ locations: true,
930
+ ecmaVersion: 6,
931
+ sourceType: "module"
932
+ });
933
+ if(!ast || typeof ast !== "object" || ast.type !== "Program")
934
+ throw new Error("evaluate: Source couldn't be parsed");
935
+ if(ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement")
936
+ throw new Error("evaluate: Source is not a expression");
937
+ return this.evaluateExpression(ast.body[0].expression);
938
+ };