evaluate the callee in CallExpression, fixes #117

This allow fancy wrappers around identifiers
This commit is contained in:
Tobias Koppers 2013-11-08 09:00:39 +01:00
parent a6a71dc90c
commit 415d161dbe
4 changed files with 78 additions and 13 deletions

View File

@ -25,6 +25,9 @@ BasicEvaluatedExpression.prototype.isConditional = function() {
BasicEvaluatedExpression.prototype.isArray = function() { BasicEvaluatedExpression.prototype.isArray = function() {
return Object.prototype.hasOwnProperty.call(this, "items"); return Object.prototype.hasOwnProperty.call(this, "items");
}; };
BasicEvaluatedExpression.prototype.isIdentifier = function() {
return Object.prototype.hasOwnProperty.call(this, "identifier");
};
BasicEvaluatedExpression.prototype.isWrapped = function() { BasicEvaluatedExpression.prototype.isWrapped = function() {
return Object.prototype.hasOwnProperty.call(this, "prefix"); return Object.prototype.hasOwnProperty.call(this, "prefix");
}; };
@ -75,6 +78,13 @@ BasicEvaluatedExpression.prototype.setRegExp = function(regExp) {
this.regExp = regExp; this.regExp = regExp;
return this; return this;
}; };
BasicEvaluatedExpression.prototype.setIdentifier = function(identifier) {
if(identifier === null)
delete this.identifier;
else
this.identifier = identifier;
return this;
};
BasicEvaluatedExpression.prototype.setWrapped = function(prefix, postfix) { BasicEvaluatedExpression.prototype.setWrapped = function(prefix, postfix) {
this.prefix = prefix; this.prefix = prefix;
this.postfix = postfix; this.postfix = postfix;

View File

@ -36,6 +36,27 @@ Parser.prototype.initializeEvaluating = function() {
if(expr.value instanceof RegExp) if(expr.value instanceof RegExp)
return new BasicEvaluatedExpression().setRegExp(expr.value).setRange(expr.range); return new BasicEvaluatedExpression().setRegExp(expr.value).setRange(expr.range);
}); });
this.plugin("evaluate LogicalExpression", function(expr) {
if(expr.operator == "&&") {
var left = this.evaluateExpression(expr.left);
var leftAsBool = left && left.asBool();
if(leftAsBool === false) return new BasicEvaluatedExpression().setBoolean(false).setRange(expr.range);
if(leftAsBool !== true) return;
var right = this.evaluateExpression(expr.right);
var rightAsBool = right && right.asBool();
if(typeof rightAsBool === "boolean")
return new BasicEvaluatedExpression().setBoolean(rightAsBool).setRange(expr.range);
} else if(expr.operator == "||") {
var left = this.evaluateExpression(expr.left);
var leftAsBool = left && left.asBool();
if(leftAsBool === true) return new BasicEvaluatedExpression().setBoolean(true).setRange(expr.range);
if(leftAsBool !== false) return;
var right = this.evaluateExpression(expr.right);
var rightAsBool = right && right.asBool();
if(typeof rightAsBool === "boolean")
return new BasicEvaluatedExpression().setBoolean(rightAsBool).setRange(expr.range);
}
});
this.plugin("evaluate BinaryExpression", function(expr) { this.plugin("evaluate BinaryExpression", function(expr) {
if(expr.operator == "+") { if(expr.operator == "+") {
var left = this.evaluateExpression(expr.left); var left = this.evaluateExpression(expr.left);
@ -179,7 +200,13 @@ Parser.prototype.initializeEvaluating = function() {
} }
}); });
this.plugin("evaluate Identifier", function(expr) { this.plugin("evaluate Identifier", function(expr) {
return this.applyPluginsBailResult("evaluate Identifier " + expr.name, expr); if(this.scope.definitions.indexOf(expr.name) == -1) {
var result = this.applyPluginsBailResult("evaluate Identifier " + expr.name, expr);
if(result) return result;
return new BasicEvaluatedExpression().setIdentifier(expr.name).setRange(expr.range);
} else {
return this.applyPluginsBailResult("evaluate defined Identifier " + expr.name, expr);
}
}); });
this.plugin("evaluate MemberExpression", function(expression) { this.plugin("evaluate MemberExpression", function(expression) {
var expr = expression; var expr = expression;
@ -188,10 +215,16 @@ Parser.prototype.initializeEvaluating = function() {
exprName.unshift(expr.property.name); exprName.unshift(expr.property.name);
expr = expr.object; expr = expr.object;
} }
if(expr.type == "Identifier" && this.scope.definitions.indexOf(expr.name) == -1) { if(expr.type == "Identifier") {
exprName.unshift(expr.name); exprName.unshift(expr.name);
exprName = exprName.join("."); exprName = exprName.join(".");
return this.applyPluginsBailResult("evaluate Identifier " + exprName, expression); if(this.scope.definitions.indexOf(expr.name) == -1) {
var result = this.applyPluginsBailResult("evaluate Identifier " + exprName, expression);
if(result) return result;
return new BasicEvaluatedExpression().setIdentifier(exprName).setRange(expression.range);
} else {
return this.applyPluginsBailResult("evaluate defined Identifier " + exprName, expression);
}
} }
}); });
this.plugin("evaluate CallExpression", function(expr) { this.plugin("evaluate CallExpression", function(expr) {
@ -491,16 +524,9 @@ Parser.prototype.walkExpression = function walkExpression(expression) {
this.walkExpressions(expression.arguments); this.walkExpressions(expression.arguments);
break; break;
case "CallExpression": case "CallExpression":
var callee = expression.callee; var callee = this.evaluateExpression(expression.callee);
var calleeName = []; if(callee.isIdentifier()) {
while(callee.type == "MemberExpression" && callee.property.type == "Identifier") { var result = this.applyPluginsBailResult("call " + callee.identifier, expression);
calleeName.unshift(callee.property.name);
callee = callee.object;
}
if(callee.type == "Identifier" && this.scope.definitions.indexOf(callee.name) == -1) {
calleeName.unshift(callee.name);
calleeName = calleeName.join(".");
var result = this.applyPluginsBailResult("call " + calleeName, expression);
if(result === true) if(result === true)
break; break;
} }

View File

@ -64,6 +64,18 @@ AMDPlugin.prototype.apply = function(compiler) {
compiler.parser.plugin("expression __webpack_amd_options__", function(expr) { compiler.parser.plugin("expression __webpack_amd_options__", function(expr) {
return this.state.current.addVariable("__webpack_amd_options__", JSON.stringify(options)); return this.state.current.addVariable("__webpack_amd_options__", JSON.stringify(options));
}); });
compiler.parser.plugin("evaluate typeof define.amd", function(expr) {
return new BasicEvaluatedExpression().setString(typeof options).setRange(expr.range);
});
compiler.parser.plugin("evaluate typeof require.amd", function(expr) {
return new BasicEvaluatedExpression().setString(typeof options).setRange(expr.range);
});
compiler.parser.plugin("evaluate Identifier define.amd", function(expr) {
return new BasicEvaluatedExpression().setBoolean(true).setRange(expr.range);
});
compiler.parser.plugin("evaluate Identifier require.amd", function(expr) {
return new BasicEvaluatedExpression().setBoolean(true).setRange(expr.range);
});
compiler.parser.plugin("evaluate typeof define", function(expr) { compiler.parser.plugin("evaluate typeof define", function(expr) {
return new BasicEvaluatedExpression().setString("function").setRange(expr.range); return new BasicEvaluatedExpression().setString("function").setRange(expr.range);
}); });

View File

@ -206,6 +206,23 @@ describe("main", function() {
var x = require(DEBUG ? "fail" : "./a"); var x = require(DEBUG ? "fail" : "./a");
var y = DEBUG ? require("fail") : require("./a"); var y = DEBUG ? require("fail") : require("./a");
}); });
it("should parse fancy function calls", function() {
("function"==typeof define && define.amd ?
define :
function(e,t){return t()}
)(["./constructor"], function(c) {
return new c(1324);
});
module.exports.should.have.property("value").be.eql(1324);
(("function"==typeof define && define.amd ?
define :
function(e,t){return t()}
)(["./constructor"], function(c) {
return new c(4231);
}));
module.exports.should.have.property("value").be.eql(4231);
});
}); });
describe("polyfilling", function() { describe("polyfilling", function() {