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.
- package/LICENSE +22 -22
- package/README.md +310 -310
- package/buildin/amd-define.js +1 -1
- package/buildin/amd-options.js +1 -1
- package/buildin/module.js +10 -10
- package/hot/dev-server.js +63 -63
- package/hot/log-apply-result.js +25 -25
- package/hot/only-dev-server.js +77 -77
- package/hot/poll.js +37 -37
- package/hot/signal.js +65 -65
- package/lib/APIPlugin.js +49 -49
- package/lib/AbstractPlugin.js +22 -22
- package/lib/AmdMainTemplatePlugin.js +43 -43
- package/lib/ArrayMap.js +50 -50
- package/lib/AsyncDependenciesBlock.js +39 -39
- package/lib/AutomaticPrefetchPlugin.js +35 -35
- package/lib/BannerPlugin.js +34 -34
- package/lib/BasicEvaluatedExpression.js +140 -140
- package/lib/CachePlugin.js +43 -43
- package/lib/CaseSensitiveModulesWarning.js +16 -16
- package/lib/Chunk.js +252 -252
- package/lib/ChunkRenderError.js +17 -17
- package/lib/ChunkTemplate.js +37 -37
- package/lib/CompatibilityPlugin.js +42 -42
- package/lib/Compilation.js +891 -891
- package/lib/Compiler.js +407 -407
- package/lib/ConcatSource.js +5 -5
- package/lib/ConstPlugin.js +54 -54
- package/lib/ContextModule.js +130 -130
- package/lib/ContextModuleFactory.js +132 -132
- package/lib/ContextReplacementPlugin.js +93 -93
- package/lib/CriticalDependenciesWarning.js +24 -24
- package/lib/DefinePlugin.js +126 -126
- package/lib/DelegatedModule.js +69 -69
- package/lib/DelegatedModuleFactoryPlugin.js +51 -51
- package/lib/DelegatedPlugin.js +21 -21
- package/lib/DependenciesBlock.js +57 -57
- package/lib/DependenciesBlockVariable.js +41 -41
- package/lib/Dependency.js +54 -54
- package/lib/DllEntryPlugin.js +32 -32
- package/lib/DllModule.js +55 -55
- package/lib/DllModuleFactory.js +18 -18
- package/lib/DllPlugin.js +30 -30
- package/lib/DllReferencePlugin.js +26 -26
- package/lib/EntryModuleNotFoundError.js +15 -15
- package/lib/EntryOptionPlugin.js +28 -28
- package/lib/EnvironmentPlugin.js +28 -28
- package/lib/EvalDevToolModulePlugin.js +17 -17
- package/lib/EvalDevToolModuleTemplatePlugin.js +29 -29
- package/lib/EvalSourceMapDevToolModuleTemplatePlugin.js +68 -68
- package/lib/EvalSourceMapDevToolPlugin.js +25 -25
- package/lib/ExtendedAPIPlugin.js +45 -45
- package/lib/ExternalModule.js +89 -89
- package/lib/ExternalModuleFactoryPlugin.js +86 -86
- package/lib/ExternalsPlugin.js +16 -16
- package/lib/FunctionModulePlugin.js +18 -18
- package/lib/FunctionModuleTemplatePlugin.js +39 -39
- package/lib/HotModuleReplacement.runtime.js +486 -486
- package/lib/HotModuleReplacementPlugin.js +223 -223
- package/lib/HotUpdateChunkTemplate.js +28 -28
- package/lib/IgnorePlugin.js +32 -32
- package/lib/JsonpChunkTemplatePlugin.js +26 -26
- package/lib/JsonpExportMainTemplatePlugin.js +28 -28
- package/lib/JsonpHotUpdateChunkTemplatePlugin.js +26 -26
- package/lib/JsonpMainTemplate.runtime.js +56 -56
- package/lib/JsonpMainTemplatePlugin.js +162 -162
- package/lib/JsonpTemplatePlugin.js +17 -17
- package/lib/LibManifestPlugin.js +49 -49
- package/lib/LibraryTemplatePlugin.js +77 -77
- package/lib/LoaderTargetPlugin.js +16 -16
- package/lib/MainTemplate.js +169 -169
- package/lib/MemoryOutputFileSystem.js +5 -5
- package/lib/Module.js +116 -116
- package/lib/ModuleFilenameHelpers.js +157 -157
- package/lib/ModuleNotFoundError.js +17 -17
- package/lib/ModuleParseError.js +26 -26
- package/lib/ModuleParserHelpers.js +21 -21
- package/lib/ModuleReason.js +9 -9
- package/lib/ModuleTemplate.js +23 -23
- package/lib/MovedToPluginWarningPlugin.js +17 -17
- package/lib/MultiCompiler.js +166 -166
- package/lib/MultiEntryPlugin.js +31 -31
- package/lib/MultiModule.js +71 -71
- package/lib/MultiModuleFactory.js +18 -18
- package/lib/NamedModulesPlugin.js +21 -21
- package/lib/NewWatchingPlugin.js +12 -12
- package/lib/NoErrorsPlugin.js +18 -18
- package/lib/NodeStuffPlugin.js +99 -99
- package/lib/NormalModule.js +322 -322
- package/lib/NormalModuleFactory.js +171 -171
- package/lib/NormalModuleReplacementPlugin.js +40 -40
- package/lib/NullFactory.js +10 -10
- package/lib/OldWatchingPlugin.js +14 -14
- package/lib/OptionsApply.js +10 -10
- package/lib/OriginalSource.js +5 -5
- package/lib/Parser.js +938 -938
- package/lib/PrefetchPlugin.js +25 -25
- package/lib/ProgressPlugin.js +80 -80
- package/lib/ProvidePlugin.js +48 -48
- package/lib/RawModule.js +65 -65
- package/lib/RawSource.js +5 -5
- package/lib/RecordIdsPlugin.js +130 -130
- package/lib/RequestShortener.js +56 -56
- package/lib/RequireJsStuffPlugin.js +38 -38
- package/lib/ResolverPlugin.js +34 -34
- package/lib/SetVarMainTemplatePlugin.js +36 -36
- package/lib/SingleEntryPlugin.js +24 -24
- package/lib/Source.js +5 -5
- package/lib/SourceMapDevToolModuleOptionsPlugin.js +33 -33
- package/lib/SourceMapDevToolPlugin.js +168 -168
- package/lib/SourceMapSource.js +5 -5
- package/lib/Stats.js +732 -732
- package/lib/Template.js +119 -119
- package/lib/TemplatedPathPlugin.js +111 -111
- package/lib/UmdMainTemplatePlugin.js +146 -146
- package/lib/UnsupportedFeatureWarning.js +14 -14
- package/lib/WarnCaseSensitiveModulesPlugin.js +27 -27
- package/lib/WatchIgnorePlugin.js +45 -45
- package/lib/WebpackOptionsApply.js +376 -376
- package/lib/WebpackOptionsDefaulter.js +112 -112
- package/lib/dependencies/AMDDefineDependency.js +63 -63
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +240 -240
- package/lib/dependencies/AMDPlugin.js +115 -115
- package/lib/dependencies/AMDRequireArrayDependency.js +34 -34
- package/lib/dependencies/AMDRequireContextDependency.js +18 -18
- package/lib/dependencies/AMDRequireDependenciesBlock.js +25 -25
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +145 -145
- package/lib/dependencies/AMDRequireDependency.js +64 -64
- package/lib/dependencies/AMDRequireItemDependency.js +17 -17
- package/lib/dependencies/CommonJsPlugin.js +93 -93
- package/lib/dependencies/CommonJsRequireContextDependency.js +18 -18
- package/lib/dependencies/CommonJsRequireDependency.js +17 -17
- package/lib/dependencies/CommonJsRequireDependencyParserPlugin.js +91 -91
- package/lib/dependencies/ConstDependency.js +29 -29
- package/lib/dependencies/ContextDependency.js +24 -24
- package/lib/dependencies/ContextDependencyHelpers.js +34 -34
- package/lib/dependencies/ContextDependencyTemplateAsId.js +22 -22
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +31 -31
- package/lib/dependencies/ContextElementDependency.js +17 -17
- package/lib/dependencies/DelegatedSourceDependency.js +14 -14
- package/lib/dependencies/DepBlockHelpers.js +41 -41
- package/lib/dependencies/DllEntryDependency.js +17 -17
- package/lib/dependencies/LabeledExportsDependency.js +21 -21
- package/lib/dependencies/LabeledModuleDependency.js +36 -36
- package/lib/dependencies/LabeledModuleDependencyParserPlugin.js +76 -76
- package/lib/dependencies/LabeledModulesPlugin.js +26 -26
- package/lib/dependencies/LoaderDependency.js +14 -14
- package/lib/dependencies/LoaderPlugin.js +61 -61
- package/lib/dependencies/LocalModule.js +19 -19
- package/lib/dependencies/LocalModuleDependency.js +23 -23
- package/lib/dependencies/LocalModulesHelpers.js +43 -43
- package/lib/dependencies/ModuleDependency.js +20 -20
- package/lib/dependencies/ModuleDependencyTemplateAsId.js +22 -22
- package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +22 -22
- package/lib/dependencies/ModuleHotAcceptDependency.js +18 -18
- package/lib/dependencies/ModuleHotDeclineDependency.js +18 -18
- package/lib/dependencies/MultiEntryDependency.js +16 -16
- package/lib/dependencies/NullDependency.js +17 -17
- package/lib/dependencies/NullDependencyTemplate.js +8 -8
- package/lib/dependencies/PrefetchDependency.js +14 -14
- package/lib/dependencies/RequireContextDependency.js +17 -17
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +33 -33
- package/lib/dependencies/RequireContextPlugin.js +64 -64
- package/lib/dependencies/RequireEnsureDependenciesBlock.js +20 -20
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +66 -66
- package/lib/dependencies/RequireEnsureDependency.js +29 -29
- package/lib/dependencies/RequireEnsureItemDependency.js +16 -16
- package/lib/dependencies/RequireEnsurePlugin.js +38 -38
- package/lib/dependencies/RequireHeaderDependency.js +25 -25
- package/lib/dependencies/RequireIncludeDependency.js +25 -25
- package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +18 -18
- package/lib/dependencies/RequireIncludePlugin.js +31 -31
- package/lib/dependencies/RequireResolveContextDependency.js +18 -18
- package/lib/dependencies/RequireResolveDependency.js +17 -17
- package/lib/dependencies/RequireResolveDependencyParserPlugin.js +69 -69
- package/lib/dependencies/RequireResolveHeaderDependency.js +25 -25
- package/lib/dependencies/SingleEntryDependency.js +14 -14
- package/lib/dependencies/TemplateArgumentDependency.js +26 -26
- package/lib/dependencies/WebpackMissingModule.js +23 -23
- package/lib/dependencies/getFunctionExpression.js +43 -43
- package/lib/node/NodeChunkTemplatePlugin.js +22 -22
- package/lib/node/NodeEnvironmentPlugin.js +25 -25
- package/lib/node/NodeHotUpdateChunkTemplatePlugin.js +24 -24
- package/lib/node/NodeMainTemplate.runtime.js +20 -20
- package/lib/node/NodeMainTemplateAsync.runtime.js +34 -34
- package/lib/node/NodeMainTemplatePlugin.js +164 -164
- package/lib/node/NodeOutputFileSystem.js +17 -17
- package/lib/node/NodeSourcePlugin.js +85 -75
- package/lib/node/NodeTargetPlugin.js +12 -12
- package/lib/node/NodeTemplatePlugin.js +21 -21
- package/lib/node/NodeWatchFileSystem.js +65 -65
- package/lib/node/OldNodeWatchFileSystem.js +265 -265
- package/lib/optimize/AggressiveMergingPlugin.js +115 -115
- package/lib/optimize/CommonsChunkPlugin.js +178 -178
- package/lib/optimize/DedupePlugin.js +227 -227
- package/lib/optimize/FlagIncludedChunksPlugin.js +24 -24
- package/lib/optimize/LimitChunkCountPlugin.js +55 -55
- package/lib/optimize/MergeDuplicateChunksPlugin.js +30 -30
- package/lib/optimize/MinChunkSizePlugin.js +61 -61
- package/lib/optimize/OccurenceOrderPlugin.js +5 -5
- package/lib/optimize/OccurrenceOrderPlugin.js +91 -91
- package/lib/optimize/RemoveEmptyChunksPlugin.js +19 -19
- package/lib/optimize/RemoveParentModulesPlugin.js +50 -50
- package/lib/optimize/UglifyJsPlugin.js +146 -146
- package/lib/removeAndDo.js +13 -13
- package/lib/web/WebEnvironmentPlugin.js +16 -16
- package/lib/webpack.js +113 -113
- package/lib/webpack.web.js +27 -27
- package/lib/webworker/WebWorkerChunkTemplatePlugin.js +26 -26
- package/lib/webworker/WebWorkerMainTemplatePlugin.js +78 -78
- package/lib/webworker/WebWorkerTemplatePlugin.js +15 -15
- 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
|
+
};
|