Concatenate strings also on the right-hand side of an expression that cannot be evaluated. Fix #126
E.g. converts: a+'Hello'+'World' to a+'HelloWorld'
This commit is contained in:
@@ -636,7 +636,8 @@ merge(Compressor.prototype, {
|
|||||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||||
if (!compressor.option("evaluate")) return [ this ];
|
if (!compressor.option("evaluate")) return [ this ];
|
||||||
try {
|
try {
|
||||||
var val = this._eval(), ast = make_node_from_constant(compressor, val, this);
|
var val = this._eval(compressor);
|
||||||
|
var ast = val instanceof AST_Binary ? val : make_node_from_constant(compressor, val, this);
|
||||||
return [ best_of(ast, this), val ];
|
return [ best_of(ast, this), val ];
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== def) throw ex;
|
if (ex !== def) throw ex;
|
||||||
@@ -653,8 +654,8 @@ merge(Compressor.prototype, {
|
|||||||
// places too. :-( Wish JS had multiple inheritance.
|
// places too. :-( Wish JS had multiple inheritance.
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
function ev(node) {
|
function ev(node, compressor) {
|
||||||
return node._eval();
|
return node._eval(compressor);
|
||||||
};
|
};
|
||||||
def(AST_Node, function(){
|
def(AST_Node, function(){
|
||||||
throw def; // not constant
|
throw def; // not constant
|
||||||
@@ -662,69 +663,87 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Constant, function(){
|
def(AST_Constant, function(){
|
||||||
return this.getValue();
|
return this.getValue();
|
||||||
});
|
});
|
||||||
def(AST_UnaryPrefix, function(){
|
def(AST_UnaryPrefix, function(compressor){
|
||||||
var e = this.expression;
|
var e = this.expression;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "!": return !ev(e);
|
case "!": return !ev(e, compressor);
|
||||||
case "typeof":
|
case "typeof":
|
||||||
// Function would be evaluated to an array and so typeof would
|
// Function would be evaluated to an array and so typeof would
|
||||||
// incorrectly return 'object'. Hence making is a special case.
|
// incorrectly return 'object'. Hence making is a special case.
|
||||||
if (e instanceof AST_Function) return typeof function(){};
|
if (e instanceof AST_Function) return typeof function(){};
|
||||||
|
|
||||||
e = ev(e);
|
e = ev(e, compressor);
|
||||||
|
|
||||||
// typeof <RegExp> returns "object" or "function" on different platforms
|
// typeof <RegExp> returns "object" or "function" on different platforms
|
||||||
// so cannot evaluate reliably
|
// so cannot evaluate reliably
|
||||||
if (e instanceof RegExp) throw def;
|
if (e instanceof RegExp) throw def;
|
||||||
|
|
||||||
return typeof e;
|
return typeof e;
|
||||||
case "void": return void ev(e);
|
case "void": return void ev(e, compressor);
|
||||||
case "~": return ~ev(e);
|
case "~": return ~ev(e, compressor);
|
||||||
case "-":
|
case "-":
|
||||||
e = ev(e);
|
e = ev(e, compressor);
|
||||||
if (e === 0) throw def;
|
if (e === 0) throw def;
|
||||||
return -e;
|
return -e;
|
||||||
case "+": return +ev(e);
|
case "+": return +ev(e, compressor);
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(){
|
def(AST_Binary, function(c){
|
||||||
var left = this.left, right = this.right;
|
var left = this.left, right = this.right;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&" : return ev(left) && ev(right);
|
case "&&" : return ev(left, c) && ev(right, c);
|
||||||
case "||" : return ev(left) || ev(right);
|
case "||" : return ev(left, c) || ev(right, c);
|
||||||
case "|" : return ev(left) | ev(right);
|
case "|" : return ev(left, c) | ev(right, c);
|
||||||
case "&" : return ev(left) & ev(right);
|
case "&" : return ev(left, c) & ev(right, c);
|
||||||
case "^" : return ev(left) ^ ev(right);
|
case "^" : return ev(left, c) ^ ev(right, c);
|
||||||
case "+" : return ev(left) + ev(right);
|
case "+" :
|
||||||
case "*" : return ev(left) * ev(right);
|
// handle concatenating strings even if the left part cannot
|
||||||
case "/" : return ev(left) / ev(right);
|
// be evaluated, e.g. (variable + "str") + "str"
|
||||||
case "%" : return ev(left) % ev(right);
|
if (!(c instanceof Compressor)) {
|
||||||
case "-" : return ev(left) - ev(right);
|
throw new Error("Compressor must be passed!!");
|
||||||
case "<<" : return ev(left) << ev(right);
|
}
|
||||||
case ">>" : return ev(left) >> ev(right);
|
if (left instanceof AST_Binary && left.operator == "+" && left.is_string(c)) {
|
||||||
case ">>>" : return ev(left) >>> ev(right);
|
return make_node(AST_Binary, this, {
|
||||||
case "==" : return ev(left) == ev(right);
|
operator: "+",
|
||||||
case "===" : return ev(left) === ev(right);
|
left: left.left,
|
||||||
case "!=" : return ev(left) != ev(right);
|
right: make_node(AST_String, null, {
|
||||||
case "!==" : return ev(left) !== ev(right);
|
value : "" + ev(left.right, c) + ev(right, c),
|
||||||
case "<" : return ev(left) < ev(right);
|
start : left.right.start,
|
||||||
case "<=" : return ev(left) <= ev(right);
|
end : right.end
|
||||||
case ">" : return ev(left) > ev(right);
|
})
|
||||||
case ">=" : return ev(left) >= ev(right);
|
});
|
||||||
case "in" : return ev(left) in ev(right);
|
} else {
|
||||||
case "instanceof" : return ev(left) instanceof ev(right);
|
return ev(left, c) + ev(right, c);
|
||||||
|
}
|
||||||
|
case "*" : return ev(left, c) * ev(right, c);
|
||||||
|
case "/" : return ev(left, c) / ev(right, c);
|
||||||
|
case "%" : return ev(left, c) % ev(right, c);
|
||||||
|
case "-" : return ev(left, c) - ev(right, c);
|
||||||
|
case "<<" : return ev(left, c) << ev(right, c);
|
||||||
|
case ">>" : return ev(left, c) >> ev(right, c);
|
||||||
|
case ">>>" : return ev(left, c) >>> ev(right, c);
|
||||||
|
case "==" : return ev(left, c) == ev(right, c);
|
||||||
|
case "===" : return ev(left, c) === ev(right, c);
|
||||||
|
case "!=" : return ev(left, c) != ev(right, c);
|
||||||
|
case "!==" : return ev(left, c) !== ev(right, c);
|
||||||
|
case "<" : return ev(left, c) < ev(right, c);
|
||||||
|
case "<=" : return ev(left, c) <= ev(right, c);
|
||||||
|
case ">" : return ev(left, c) > ev(right, c);
|
||||||
|
case ">=" : return ev(left, c) >= ev(right, c);
|
||||||
|
case "in" : return ev(left, c) in ev(right, c);
|
||||||
|
case "instanceof" : return ev(left, c) instanceof ev(right, c);
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(){
|
def(AST_Conditional, function(compressor){
|
||||||
return ev(this.condition)
|
return ev(this.condition, compressor)
|
||||||
? ev(this.consequent)
|
? ev(this.consequent, compressor)
|
||||||
: ev(this.alternative);
|
: ev(this.alternative, compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(){
|
def(AST_SymbolRef, function(compressor){
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
if (d && d.constant && d.init) return ev(d.init);
|
if (d && d.constant && d.init) return ev(d.init, compressor);
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
|
|||||||
22
test/compress/issue-126.js
Normal file
22
test/compress/issue-126.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
concatenate_rhs_strings: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
foo(bar() + 123 + "Hello" + "World");
|
||||||
|
foo(bar() + (123 + "Hello") + "World");
|
||||||
|
foo((bar() + 123) + "Hello" + "World");
|
||||||
|
foo(bar() + 123 + "Hello" + "World" + ("Foo" + "Bar"));
|
||||||
|
foo("Foo" + "Bar" + bar() + 123 + "Hello" + "World" + ("Foo" + "Bar"));
|
||||||
|
foo("Hello" + bar() + 123 + "World");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo(bar() + 123 + "HelloWorld");
|
||||||
|
foo(bar() + "123HelloWorld");
|
||||||
|
foo((bar() + 123) + "HelloWorld");
|
||||||
|
foo(bar() + 123 + "HelloWorldFooBar");
|
||||||
|
foo("FooBar" + bar() + "123HelloWorldFooBar");
|
||||||
|
foo("Hello" + bar() + "123World");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user