Skip to content

Commit 63f40c0

Browse files
committed
support fancy array in AMD, support .replace and .split
1 parent 9b77262 commit 63f40c0

9 files changed

+191
-84
lines changed

lib/BasicEvaluatedExpression.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ BasicEvaluatedExpression.prototype.isConditional = function() {
2525
BasicEvaluatedExpression.prototype.isArray = function() {
2626
return Object.prototype.hasOwnProperty.call(this, "items");
2727
};
28+
BasicEvaluatedExpression.prototype.isConstArray = function() {
29+
return Object.prototype.hasOwnProperty.call(this, "array");
30+
};
2831
BasicEvaluatedExpression.prototype.isIdentifier = function() {
2932
return Object.prototype.hasOwnProperty.call(this, "identifier");
3033
};
@@ -37,6 +40,7 @@ BasicEvaluatedExpression.prototype.asBool = function() {
3740
else if(this.isNumber()) return !!this.number;
3841
else if(this.isRegExp()) return true;
3942
else if(this.isArray()) return true;
43+
else if(this.isConstArray()) return true;
4044
else if(this.isWrapped()) return this.prefix || this.postfix ? true : undefined;
4145
return undefined;
4246
};
@@ -45,9 +49,7 @@ BasicEvaluatedExpression.prototype.set = function(value) {
4549
if(typeof value === "number") return this.setNumber(value);
4650
if(typeof value === "boolean") return this.setBoolean(value);
4751
if(value instanceof RegExp) return this.setRegExp(value);
48-
if(Array.isArray(value)) return this.setItems(value.map(function(item) {
49-
return new BasicEvaluatedExpression().set(item);
50-
}));
52+
if(Array.isArray(value)) return this.setArray(value);
5153
return this;
5254
};
5355
BasicEvaluatedExpression.prototype.setString = function(str) {
@@ -109,6 +111,13 @@ BasicEvaluatedExpression.prototype.setItems = function(items) {
109111
this.items = items;
110112
return this;
111113
};
114+
BasicEvaluatedExpression.prototype.setArray = function(array) {
115+
if(array === null)
116+
delete this.array;
117+
else
118+
this.array = array;
119+
return this;
120+
};
112121
BasicEvaluatedExpression.prototype.addOptions = function(options) {
113122
if(!this.options) this.options = [];
114123
options.forEach(function(item) {

lib/Parser.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ Parser.prototype.initializeEvaluating = function() {
186186
if(arg.isString() || arg.isWrapped()) return new BasicEvaluatedExpression().setString("string").setRange(expr.range);
187187
else if(arg.isNumber()) return new BasicEvaluatedExpression().setString("number").setRange(expr.range);
188188
else if(arg.isBoolean()) return new BasicEvaluatedExpression().setString("boolean").setRange(expr.range);
189-
else if(arg.isArray() || arg.isRegExp()) return new BasicEvaluatedExpression().setString("object").setRange(expr.range);
189+
else if(arg.isArray() || arg.isConstArray() || arg.isRegExp()) return new BasicEvaluatedExpression().setString("object").setRange(expr.range);
190190
} else if(expr.operator == "!") {
191191
var argument = this.evaluateExpression(expr.argument);
192192
if(!argument) return;
@@ -234,6 +234,17 @@ Parser.prototype.initializeEvaluating = function() {
234234
if(!param) return;
235235
return this.applyPluginsBailResult("evaluate CallExpression ." + expr.callee.property.name, expr, param);
236236
});
237+
this.plugin("evaluate CallExpression .replace", function(expr, param) {
238+
if(!param.isString()) return;
239+
if(expr.arguments.length !== 2) return;
240+
var arg1 = this.evaluateExpression(expr.arguments[0]);
241+
var arg2 = this.evaluateExpression(expr.arguments[1]);
242+
if(!arg1.isString() && !arg1.isRegExp()) return;
243+
arg1 = arg1.regExp || arg1.string;
244+
if(!arg2.isString()) return;
245+
arg2 = arg2.string;
246+
return new BasicEvaluatedExpression().setString(param.string.replace(arg1, arg2)).setRange(expr.range);
247+
});
237248
this.plugin("evaluate CallExpression .substr", function(expr, param) {
238249
if(!param.isString()) return;
239250
var result, str = param.string;
@@ -276,6 +287,18 @@ Parser.prototype.initializeEvaluating = function() {
276287
}
277288
return new BasicEvaluatedExpression().setString(result).setRange(expr.range);
278289
});
290+
this.plugin("evaluate CallExpression .split", function(expr, param) {
291+
if(!param.isString()) return;
292+
if(expr.arguments.length !== 1) return;
293+
var result;
294+
var arg = this.evaluateExpression(expr.arguments[0]);
295+
if(arg.isString()) {
296+
result = param.string.split(arg.string);
297+
} else if(arg.isRegExp()) {
298+
result = param.string.split(arg.regExp);
299+
} else return;
300+
return new BasicEvaluatedExpression().setArray(result).setRange(expr.range);
301+
});
279302
this.plugin("evaluate ConditionalExpression", function(expr) {
280303
var condition = this.evaluateExpression(expr.test);
281304
var conditionValue = condition.asBool();

lib/dependencies/AMDDefineDependencyParserPlugin.js

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,38 @@ module.exports = AbstractPlugin.create({
2626
}
2727
break;
2828
case 2:
29-
if(expr.arguments[0].type == "ArrayExpression") {
30-
// define([...], f() {...})
31-
array = expr.arguments[0];
32-
fn = expr.arguments[1];
33-
} else if(expr.arguments[0].type == "Literal" && expr.arguments[1].type == "ArrayExpression") {
34-
// define("...", [...])
35-
array = expr.arguments[1];
36-
} else if(expr.arguments[0].type == "Literal" && expr.arguments[1].type == "FunctionExpression") {
37-
// define("...", f() {...})
38-
fn = expr.arguments[1];
39-
} else if(expr.arguments[0].type == "Literal") {
40-
// define("...", {...})
41-
var dep = new AMDDefineDependency(expr.range, expr.arguments[1].range);
42-
dep.loc = expr.loc;
43-
this.state.current.addDependency(dep);
44-
return true;
29+
if(expr.arguments[0].type === "Literal") {
30+
if(expr.arguments[1].type == "FunctionExpression") {
31+
// define("...", f() {...})
32+
fn = expr.arguments[1];
33+
} else {
34+
// define("...", {...})
35+
var dep = new AMDDefineDependency(expr.range, expr.arguments[1].range);
36+
dep.loc = expr.loc;
37+
this.state.current.addDependency(dep);
38+
return true;
39+
}
40+
} else {
41+
if(expr.arguments[1].type == "FunctionExpression") {
42+
// define([...], f() {...})
43+
array = expr.arguments[0];
44+
fn = expr.arguments[1];
45+
} else {
46+
return;
47+
}
4548
}
4649
break;
4750
case 3:
48-
if(expr.arguments[0].type == "Literal" &&
49-
expr.arguments[1].type == "ArrayExpression") {
50-
// define("...", [...], f() {...})
51-
array = expr.arguments[1];
52-
fn = expr.arguments[2];
53-
}
51+
// define("...", [...], f() {...})
52+
array = expr.arguments[1];
53+
fn = expr.arguments[2];
5454
break;
5555
}
5656
if(!array && !fn) return;
5757
if(array) {
5858
var param = this.evaluateExpression(array);
59-
param.items.forEach(function(param) {
60-
var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
61-
if(result === undefined) {
62-
this.applyPluginsBailResult("call define:amd:context", expr, param);
63-
}
64-
}, this);
59+
var result = this.applyPluginsBailResult("call define:amd:array", expr, param);
60+
if(!result) return;
6561
}
6662
if(fn && fn.type === "FunctionExpression") {
6763
var inTry = this.scope.inTry;
@@ -80,6 +76,36 @@ module.exports = AbstractPlugin.create({
8076
this.state.current.addDependency(dep);
8177
return true;
8278
},
79+
"call define:amd:array": function(expr, param) {
80+
if(param.isArray()) {
81+
param.items.forEach(function(param) {
82+
var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
83+
if(result === undefined) {
84+
this.applyPluginsBailResult("call define:amd:context", expr, param);
85+
}
86+
}, this);
87+
return true;
88+
} else if(param.isConstArray()) {
89+
var deps = [];
90+
param.array.forEach(function(request) {
91+
var dep;
92+
if(["require", "exports", "module"].indexOf(request) >= 0) {
93+
dep = request;
94+
} else {
95+
dep = new AMDRequireItemDependency(request);
96+
dep.loc = expr.loc;
97+
dep.optional = !!this.scope.inTry;
98+
this.state.current.addDependency(dep);
99+
}
100+
deps.push(dep);
101+
}, this);
102+
var dep = new AMDRequireArrayDependency(deps, param.range);
103+
dep.loc = expr.loc;
104+
dep.optional = !!this.scope.inTry;
105+
this.state.current.addDependency(dep);
106+
return true;
107+
}
108+
},
83109
"call define:amd:item": function(expr, param) {
84110
if(param.isConditional()) {
85111
param.options.forEach(function(param) {

lib/dependencies/AMDPlugin.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
var path = require("path");
66
var AMDRequireDependency = require("./AMDRequireDependency");
77
var AMDRequireItemDependency = require("./AMDRequireItemDependency");
8+
var AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
89
var AMDRequireContextDependency = require("./AMDRequireContextDependency");
910
var AMDDefineDependency = require("./AMDDefineDependency");
1011
var ConstDependency = require("./ConstDependency");
@@ -35,6 +36,9 @@ AMDPlugin.prototype.apply = function(compiler) {
3536
compilation.dependencyFactories.set(AMDRequireItemDependency, normalModuleFactory);
3637
compilation.dependencyTemplates.set(AMDRequireItemDependency, new AMDRequireItemDependency.Template());
3738

39+
compilation.dependencyFactories.set(AMDRequireArrayDependency, new NullFactory());
40+
compilation.dependencyTemplates.set(AMDRequireArrayDependency, new AMDRequireArrayDependency.Template());
41+
3842
compilation.dependencyFactories.set(AMDRequireContextDependency, contextModuleFactory);
3943
compilation.dependencyTemplates.set(AMDRequireContextDependency, new AMDRequireContextDependency.Template());
4044

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
var Dependency = require("../Dependency");
6+
7+
function AMDRequireArrayDependency(depsArray, range) {
8+
Dependency.call(this);
9+
this.Class = AMDRequireArrayDependency;
10+
this.depsArray = depsArray;
11+
this.range = range;
12+
}
13+
module.exports = AMDRequireArrayDependency;
14+
15+
AMDRequireArrayDependency.prototype = Object.create(Dependency.prototype);
16+
AMDRequireArrayDependency.prototype.type = "amd require array";
17+
18+
AMDRequireArrayDependency.Template = function AMDRequireArrayDependencyTemplate() {};
19+
20+
AMDRequireArrayDependency.Template.prototype.apply = function(dep, source, outputOptions, requestShortener) {
21+
var content = "[" + dep.depsArray.map(function(dep) {
22+
if(typeof dep === "string") {
23+
return dep;
24+
} else {
25+
var comment = "";
26+
if(outputOptions.pathinfo) comment = "/*! " + requestShortener.shorten(dep.request) + " */ ";
27+
if(dep.module)
28+
return "require(" + comment + dep.module.id + ")";
29+
else
30+
return "(function webpackMissingModule() { throw new Error(" + JSON.stringify("Cannot find module \"" + dep.request + "\"") + "); }())";
31+
}
32+
}).join(", ") + "]";
33+
source.replace(dep.range[0], dep.range[1]-1, content);
34+
};

lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
var AbstractPlugin = require("../AbstractPlugin");
66
var AMDRequireItemDependency = require("./AMDRequireItemDependency");
7+
var AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
78
var AMDRequireContextDependency = require("./AMDRequireContextDependency");
89
var AMDRequireDependenciesBlock = require("./AMDRequireDependenciesBlock");
910
var ContextDependencyHelpers = require("./ContextDependencyHelpers");
@@ -12,66 +13,31 @@ module.exports = AbstractPlugin.create({
1213
"call require": function(expr) {
1314
switch(expr.arguments.length) {
1415
case 1:
15-
if(expr.arguments[0].type == "FunctionExpression") {
16-
var dep = new AMDRequireDependenciesBlock(expr, param.range, null, expr.arguments[0].range);
17-
dep.loc = expr.loc;
18-
var old = this.state.current;
19-
this.state.current = dep;
20-
this.inScope([], function() {
21-
param.items.forEach(function(param) {
22-
var result = this.applyPluginsBailResult("call require:amd:item", expr, param);
23-
if(result === undefined) {
24-
this.applyPluginsBailResult("call require:amd:context", expr, param);
25-
}
26-
}, this);
27-
}.bind(this));
28-
this.inScope(expr.arguments[0].params.filter(function(i) {
29-
return ["require", "module", "exports"].indexOf(i.name) < 0;
30-
}), function() {
31-
if(expr.arguments[0].body.type === "BlockStatement")
32-
this.walkStatement(expr.arguments[0].body);
33-
else
34-
this.walkExpression(expr.arguments[0].body);
35-
}.bind(this));
36-
this.state.current = old;
37-
this.state.current.addBlock(dep);
38-
return true;
39-
}
4016
var param = this.evaluateExpression(expr.arguments[0]);
41-
if(param.isArray()) {
42-
var dep = new AMDRequireDependenciesBlock(expr, param.range);
43-
dep.loc = expr.loc;
44-
var old = this.state.current;
45-
this.state.current = dep;
46-
this.inScope([], function() {
47-
param.items.forEach(function(param) {
48-
var result = this.applyPluginsBailResult("call require:amd:item", expr, param);
49-
if(result === undefined) {
50-
this.applyPluginsBailResult("call require:amd:context", expr, param);
51-
}
52-
}, this);
53-
}.bind(this));
54-
this.state.current = old;
55-
this.state.current.addBlock(dep);
56-
return true;
57-
}
58-
return;
17+
var result;
18+
var dep = new AMDRequireDependenciesBlock(expr, param.range);
19+
dep.loc = expr.loc;
20+
var old = this.state.current;
21+
this.state.current = dep;
22+
this.inScope([], function() {
23+
result = this.applyPluginsBailResult("call require:amd:array", expr, param);
24+
}.bind(this));
25+
this.state.current = old;
26+
if(!result) return;
27+
this.state.current.addBlock(dep);
28+
return true;
5929
case 2:
6030
var param = this.evaluateExpression(expr.arguments[0]);
61-
if(!param.isArray()) return;
6231
var dep = new AMDRequireDependenciesBlock(expr, param.range, expr.arguments[1].range);
6332
dep.loc = expr.loc;
6433
var old = this.state.current;
6534
this.state.current = dep;
6635
try {
36+
var result;
6737
this.inScope([], function() {
68-
param.items.forEach(function(param) {
69-
var result = this.applyPluginsBailResult("call require:amd:item", expr, param);
70-
if(result === undefined) {
71-
this.applyPluginsBailResult("call require:amd:context", expr, param);
72-
}
73-
}, this);
38+
result = this.applyPluginsBailResult("call require:amd:array", expr, param);
7439
}.bind(this));
40+
if(!result) return;
7541
if(expr.arguments[1].type === "FunctionExpression") {
7642
this.inScope(expr.arguments[1].params.filter(function(i) {
7743
return ["require", "module", "exports"].indexOf(i.name) < 0;
@@ -89,6 +55,36 @@ module.exports = AbstractPlugin.create({
8955
return true;
9056
}
9157
},
58+
"call require:amd:array": function(expr, param) {
59+
if(param.isArray()) {
60+
param.items.forEach(function(param) {
61+
var result = this.applyPluginsBailResult("call require:amd:item", expr, param);
62+
if(result === undefined) {
63+
this.applyPluginsBailResult("call require:amd:context", expr, param);
64+
}
65+
}, this);
66+
return true;
67+
} else if(param.isConstArray()) {
68+
var deps = [];
69+
param.array.forEach(function(request) {
70+
var dep;
71+
if(["require", "exports", "module"].indexOf(request) >= 0) {
72+
dep = request;
73+
} else {
74+
dep = new AMDRequireItemDependency(request);
75+
dep.loc = expr.loc;
76+
dep.optional = !!this.scope.inTry;
77+
this.state.current.addDependency(dep);
78+
}
79+
deps.push(dep);
80+
}, this);
81+
var dep = new AMDRequireArrayDependency(deps, param.range);
82+
dep.loc = expr.loc;
83+
dep.optional = !!this.scope.inTry;
84+
this.state.current.addDependency(dep);
85+
return true;
86+
}
87+
},
9288
"call require:amd:item": function(expr, param) {
9389
if(param.isConditional()) {
9490
param.options.forEach(function(param) {

lib/dependencies/ModuleDependencyTemplateAsId.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ function ModuleDependencyTemplateAsId() {}
66
module.exports = ModuleDependencyTemplateAsId;
77

88
ModuleDependencyTemplateAsId.prototype.apply = function(dep, source, outputOptions, requestShortener) {
9+
if(!dep.range) return;
910
var comment = "";
1011
if(outputOptions.pathinfo) comment = "/*! " + requestShortener.shorten(dep.request) + " */ ";
1112
if(dep.module)
@@ -16,5 +17,6 @@ ModuleDependencyTemplateAsId.prototype.apply = function(dep, source, outputOptio
1617
};
1718

1819
ModuleDependencyTemplateAsId.prototype.applyAsTemplateArgument = function(name, dep, source, outputOptions, requestShortener) {
20+
if(!dep.range) return;
1921
source.replace(dep.range[0], dep.range[1]-1, name);
2022
};

0 commit comments

Comments
 (0)