Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36b2d35bf3 | ||
|
|
79c60032a5 | ||
|
|
a3754068dd | ||
|
|
2ba5f391e0 | ||
|
|
87119e44a0 | ||
|
|
b499e03f82 | ||
|
|
a478f275e4 | ||
|
|
e9e76dcf04 | ||
|
|
0dcedad2d5 |
@@ -736,6 +736,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||||
example: `/*@__PURE__*/foo();`
|
example: `/*@__PURE__*/foo();`
|
||||||
|
|
||||||
|
- `strings` (default: `true`) -- compact string concatenations.
|
||||||
|
|
||||||
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||||
|
|
||||||
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
|
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
|
||||||
|
|||||||
285
lib/compress.js
285
lib/compress.js
@@ -83,6 +83,7 @@ function Compressor(options, false_by_default) {
|
|||||||
reduce_vars : !false_by_default,
|
reduce_vars : !false_by_default,
|
||||||
sequences : !false_by_default,
|
sequences : !false_by_default,
|
||||||
side_effects : !false_by_default,
|
side_effects : !false_by_default,
|
||||||
|
strings : !false_by_default,
|
||||||
switches : !false_by_default,
|
switches : !false_by_default,
|
||||||
top_retain : null,
|
top_retain : null,
|
||||||
toplevel : !!(options && options["top_retain"]),
|
toplevel : !!(options && options["top_retain"]),
|
||||||
@@ -1093,6 +1094,7 @@ merge(Compressor.prototype, {
|
|||||||
collapse(statements, compressor);
|
collapse(statements, compressor);
|
||||||
}
|
}
|
||||||
} while (CHANGED && max_iter-- > 0);
|
} while (CHANGED && max_iter-- > 0);
|
||||||
|
return statements;
|
||||||
|
|
||||||
function find_loop_scope_try() {
|
function find_loop_scope_try() {
|
||||||
var node = compressor.self(), level = 0;
|
var node = compressor.self(), level = 0;
|
||||||
@@ -1149,11 +1151,10 @@ merge(Compressor.prototype, {
|
|||||||
if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
|
if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node;
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
var hit_rhs;
|
var hit_rhs;
|
||||||
if (can_replace
|
if (!(node instanceof AST_SymbolDeclaration)
|
||||||
&& !(node instanceof AST_SymbolDeclaration)
|
|
||||||
&& (scan_lhs && lhs.equivalent_to(node)
|
&& (scan_lhs && lhs.equivalent_to(node)
|
||||||
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
||||||
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
if (!can_replace || stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||||
if (!hit_rhs || !value_def) abort = true;
|
if (!hit_rhs || !value_def) abort = true;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1381,7 +1382,34 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_last_node(node, parent) {
|
function is_last_node(node, parent) {
|
||||||
if (node instanceof AST_Call) return true;
|
if (node instanceof AST_Call) {
|
||||||
|
var fn = node.expression;
|
||||||
|
if (fn instanceof AST_SymbolRef) fn = fn.fixed_value();
|
||||||
|
if (!(fn instanceof AST_Lambda)) return true;
|
||||||
|
if (fn.collapse_scanning) return false;
|
||||||
|
fn.collapse_scanning = true;
|
||||||
|
var replace = can_replace;
|
||||||
|
can_replace = false;
|
||||||
|
var after = stop_after;
|
||||||
|
var if_hit = stop_if_hit;
|
||||||
|
var rhs_fn = scan_rhs;
|
||||||
|
for (var i = 0; !abort && i < fn.body.length; i++) {
|
||||||
|
var stat = fn.body[i];
|
||||||
|
if (stat instanceof AST_Return) {
|
||||||
|
if (stat.value) stat.value.transform(scanner);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stat.transform(scanner);
|
||||||
|
}
|
||||||
|
scan_rhs = rhs_fn;
|
||||||
|
stop_if_hit = if_hit;
|
||||||
|
stop_after = after;
|
||||||
|
can_replace = replace;
|
||||||
|
delete fn.collapse_scanning;
|
||||||
|
if (!abort) return false;
|
||||||
|
abort = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Exit) {
|
if (node instanceof AST_Exit) {
|
||||||
if (in_try) {
|
if (in_try) {
|
||||||
if (in_try.bfinally) return true;
|
if (in_try.bfinally) return true;
|
||||||
@@ -3826,12 +3854,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Block, function(self, compressor) {
|
OPT(AST_Block, function(self, compressor) {
|
||||||
tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_BlockStatement, function(self, compressor) {
|
OPT(AST_BlockStatement, function(self, compressor) {
|
||||||
tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1: return self.body[0];
|
case 1: return self.body[0];
|
||||||
case 0: return make_node(AST_EmptyStatement, self);
|
case 0: return make_node(AST_EmptyStatement, self);
|
||||||
@@ -3840,7 +3868,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Lambda, function(self, compressor) {
|
OPT(AST_Lambda, function(self, compressor) {
|
||||||
tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
if (compressor.option("side_effects")
|
if (compressor.option("side_effects")
|
||||||
&& self.body.length == 1
|
&& self.body.length == 1
|
||||||
&& self.body[0] === compressor.has_directive("use strict")) {
|
&& self.body[0] === compressor.has_directive("use strict")) {
|
||||||
@@ -4453,7 +4481,7 @@ merge(Compressor.prototype, {
|
|||||||
var ev = value.is_truthy() || value.tail_node().evaluate(compressor);
|
var ev = value.is_truthy() || value.tail_node().evaluate(compressor);
|
||||||
if (!ev) {
|
if (!ev) {
|
||||||
value = value.drop_side_effect_free(compressor);
|
value = value.drop_side_effect_free(compressor);
|
||||||
if (node.value !== value) node.value = value ? make_sequence(node.value, [
|
node.value = value ? make_sequence(node.value, [
|
||||||
value,
|
value,
|
||||||
make_node(AST_Number, node.value, {
|
make_node(AST_Number, node.value, {
|
||||||
value: 0
|
value: 0
|
||||||
@@ -4461,7 +4489,7 @@ merge(Compressor.prototype, {
|
|||||||
]) : null;
|
]) : null;
|
||||||
} else if (ev && !(ev instanceof AST_Node)) {
|
} else if (ev && !(ev instanceof AST_Node)) {
|
||||||
value = value.drop_side_effect_free(compressor);
|
value = value.drop_side_effect_free(compressor);
|
||||||
if (node.value !== value) node.value = value ? make_sequence(node.value, [
|
node.value = value ? make_sequence(node.value, [
|
||||||
value,
|
value,
|
||||||
make_node(AST_Number, node.value, {
|
make_node(AST_Number, node.value, {
|
||||||
value: 1
|
value: 1
|
||||||
@@ -5344,7 +5372,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Try, function(self, compressor) {
|
OPT(AST_Try, function(self, compressor) {
|
||||||
tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
||||||
if (compressor.option("dead_code") && all(self.body, is_empty)) {
|
if (compressor.option("dead_code") && all(self.body, is_empty)) {
|
||||||
var body = [];
|
var body = [];
|
||||||
@@ -5399,25 +5427,32 @@ merge(Compressor.prototype, {
|
|||||||
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Call.DEFMETHOD("lift_sequences", function(compressor) {
|
function lift_sequence_in_expression(node, compressor) {
|
||||||
if (!compressor.option("sequences")) return this;
|
var exp = node.expression;
|
||||||
var exp = this.expression;
|
if (!(exp instanceof AST_Sequence)) return node;
|
||||||
if (!(exp instanceof AST_Sequence)) return this;
|
var x = exp.expressions.slice();
|
||||||
var tail = exp.tail_node();
|
var e = node.clone();
|
||||||
if (needs_unbinding(compressor, tail) && !(this instanceof AST_New)) return this;
|
e.expression = x.pop();
|
||||||
var expressions = exp.expressions.slice(0, -1);
|
x.push(e);
|
||||||
var node = this.clone();
|
return make_sequence(node, x);
|
||||||
node.expression = tail;
|
}
|
||||||
expressions.push(node);
|
|
||||||
return make_sequence(this, expressions).optimize(compressor);
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor) {
|
OPT(AST_Call, function(self, compressor) {
|
||||||
var seq = self.lift_sequences(compressor);
|
|
||||||
if (seq !== self) {
|
|
||||||
return seq;
|
|
||||||
}
|
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
|
if (compressor.option("sequences")) {
|
||||||
|
if (exp instanceof AST_PropAccess) {
|
||||||
|
var seq = lift_sequence_in_expression(exp, compressor);
|
||||||
|
if (seq !== exp) {
|
||||||
|
var call = self.clone();
|
||||||
|
call.expression = seq.expressions.pop();
|
||||||
|
seq.expressions.push(call);
|
||||||
|
return seq.optimize(compressor);
|
||||||
|
}
|
||||||
|
} else if (!needs_unbinding(compressor, exp.tail_node())) {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
|
}
|
||||||
var fn = exp;
|
var fn = exp;
|
||||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
||||||
fn = fn.fixed_value();
|
fn = fn.fixed_value();
|
||||||
@@ -5988,9 +6023,9 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_New, function(self, compressor) {
|
OPT(AST_New, function(self, compressor) {
|
||||||
var seq = self.lift_sequences(compressor);
|
if (compressor.option("sequences")) {
|
||||||
if (seq !== self) {
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
return seq;
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
@@ -6046,21 +6081,16 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Unary.DEFMETHOD("lift_sequences", function(compressor) {
|
|
||||||
if (compressor.option("sequences") && this.expression instanceof AST_Sequence) {
|
|
||||||
var x = this.expression.expressions.slice();
|
|
||||||
var e = this.clone();
|
|
||||||
e.expression = x.pop();
|
|
||||||
x.push(e);
|
|
||||||
return make_sequence(this, x).optimize(compressor);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_UnaryPostfix, function(self, compressor) {
|
OPT(AST_UnaryPostfix, function(self, compressor) {
|
||||||
return self.lift_sequences(compressor);
|
if (compressor.option("sequences")) {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var SIGN_OPS = makePredicate("+ -");
|
||||||
|
var MULTIPLICATIVE_OPS = makePredicate("* / %");
|
||||||
OPT(AST_UnaryPrefix, function(self, compressor) {
|
OPT(AST_UnaryPrefix, function(self, compressor) {
|
||||||
var e = self.expression;
|
var e = self.expression;
|
||||||
if (compressor.option("evaluate")
|
if (compressor.option("evaluate")
|
||||||
@@ -6075,9 +6105,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
|
return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
|
||||||
}
|
}
|
||||||
var seq = self.lift_sequences(compressor);
|
if (compressor.option("sequences")) {
|
||||||
if (seq !== self) {
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
return seq;
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && self.operator == "void") {
|
if (compressor.option("side_effects") && self.operator == "void") {
|
||||||
e = e.drop_side_effect_free(compressor);
|
e = e.drop_side_effect_free(compressor);
|
||||||
@@ -6111,12 +6141,12 @@ merge(Compressor.prototype, {
|
|||||||
])).optimize(compressor);
|
])).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "-" && e instanceof AST_Infinity) {
|
if (self.operator == "-" && e instanceof AST_Infinity) e = e.transform(compressor);
|
||||||
e = e.transform(compressor);
|
if (compressor.option("evaluate")
|
||||||
}
|
&& e instanceof AST_Binary
|
||||||
if (e instanceof AST_Binary
|
&& SIGN_OPS[self.operator]
|
||||||
&& (self.operator == "+" || self.operator == "-")
|
&& MULTIPLICATIVE_OPS[e.operator]
|
||||||
&& (e.operator == "*" || e.operator == "/" || e.operator == "%")) {
|
&& (e.left.is_constant() || !e.right.has_side_effects(compressor))) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: e.operator,
|
operator: e.operator,
|
||||||
left: make_node(AST_UnaryPrefix, e.left, {
|
left: make_node(AST_UnaryPrefix, e.left, {
|
||||||
@@ -6188,6 +6218,18 @@ merge(Compressor.prototype, {
|
|||||||
self.right = tmp;
|
self.right = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function swap_chain() {
|
||||||
|
var rhs = self.right;
|
||||||
|
self.left = make_node(AST_Binary, self, {
|
||||||
|
operator: self.operator,
|
||||||
|
left: self.left,
|
||||||
|
right: rhs.left,
|
||||||
|
start: self.left.start,
|
||||||
|
end: rhs.left.end
|
||||||
|
});
|
||||||
|
self.right = rhs.right;
|
||||||
|
self.left = self.left.transform(compressor);
|
||||||
|
}
|
||||||
if (commutativeOperators[self.operator]
|
if (commutativeOperators[self.operator]
|
||||||
&& self.right.is_constant()
|
&& self.right.is_constant()
|
||||||
&& !self.left.is_constant()
|
&& !self.left.is_constant()
|
||||||
@@ -6198,7 +6240,8 @@ merge(Compressor.prototype, {
|
|||||||
// result. hence, force switch.
|
// result. hence, force switch.
|
||||||
reverse();
|
reverse();
|
||||||
}
|
}
|
||||||
self = self.lift_sequences(compressor);
|
var seq = self.lift_sequences(compressor);
|
||||||
|
if (seq !== self) return seq;
|
||||||
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
||||||
var assign = self.right;
|
var assign = self.right;
|
||||||
// a || (a = x) => a = a || x
|
// a || (a = x) => a = a || x
|
||||||
@@ -6338,17 +6381,28 @@ merge(Compressor.prototype, {
|
|||||||
case ">=": reverse("<="); break;
|
case ">=": reverse("<="); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "+") {
|
// x && (y && z) => x && y && z
|
||||||
|
// x || (y || z) => x || y || z
|
||||||
|
if (compressor.option("conditionals")
|
||||||
|
&& lazy_op[self.operator]
|
||||||
|
&& self.right instanceof AST_Binary
|
||||||
|
&& self.operator == self.right.operator) {
|
||||||
|
swap_chain();
|
||||||
|
}
|
||||||
|
if (compressor.option("strings") && self.operator == "+") {
|
||||||
|
// "foo" + 42 + "" => "foo" + 42
|
||||||
if (self.right instanceof AST_String
|
if (self.right instanceof AST_String
|
||||||
&& self.right.value == ""
|
&& self.right.value == ""
|
||||||
&& self.left.is_string(compressor)) {
|
&& self.left.is_string(compressor)) {
|
||||||
return self.left.optimize(compressor);
|
return self.left.optimize(compressor);
|
||||||
}
|
}
|
||||||
|
// "" + ("foo" + 42) => "foo" + 42
|
||||||
if (self.left instanceof AST_String
|
if (self.left instanceof AST_String
|
||||||
&& self.left.value == ""
|
&& self.left.value == ""
|
||||||
&& self.right.is_string(compressor)) {
|
&& self.right.is_string(compressor)) {
|
||||||
return self.right.optimize(compressor);
|
return self.right.optimize(compressor);
|
||||||
}
|
}
|
||||||
|
// "" + 42 + "foo" => 42 + "foo"
|
||||||
if (self.left instanceof AST_Binary
|
if (self.left instanceof AST_Binary
|
||||||
&& self.left.operator == "+"
|
&& self.left.operator == "+"
|
||||||
&& self.left.left instanceof AST_String
|
&& self.left.left instanceof AST_String
|
||||||
@@ -6357,6 +6411,15 @@ merge(Compressor.prototype, {
|
|||||||
self.left = self.left.right;
|
self.left = self.left.right;
|
||||||
return self.optimize(compressor);
|
return self.optimize(compressor);
|
||||||
}
|
}
|
||||||
|
// "x" + (y + "z") => "x" + y + "z"
|
||||||
|
// x + ("y" + z) => x + "y" + z
|
||||||
|
if (self.right instanceof AST_Binary
|
||||||
|
&& self.operator == self.right.operator
|
||||||
|
&& (self.left.is_string(compressor) && self.right.is_string(compressor)
|
||||||
|
|| self.right.left.is_string(compressor)
|
||||||
|
&& (self.left.is_constant() || !self.right.right.has_side_effects(compressor)))) {
|
||||||
|
swap_chain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate")) {
|
if (compressor.option("evaluate")) {
|
||||||
var associative = true;
|
var associative = true;
|
||||||
@@ -6727,26 +6790,6 @@ merge(Compressor.prototype, {
|
|||||||
return node.optimize(compressor);
|
return node.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// x && (y && z) => x && y && z
|
|
||||||
// x || (y || z) => x || y || z
|
|
||||||
// x + ("y" + z) => x + "y" + z
|
|
||||||
// "x" + (y + "z") => "x" + y + "z"
|
|
||||||
if (self.right instanceof AST_Binary
|
|
||||||
&& self.right.operator == self.operator
|
|
||||||
&& (lazy_op[self.operator]
|
|
||||||
|| (self.operator == "+"
|
|
||||||
&& (self.right.left.is_string(compressor)
|
|
||||||
|| (self.left.is_string(compressor)
|
|
||||||
&& self.right.right.is_string(compressor))))))
|
|
||||||
{
|
|
||||||
self.left = make_node(AST_Binary, self.left, {
|
|
||||||
operator : self.operator,
|
|
||||||
left : self.left,
|
|
||||||
right : self.right.left
|
|
||||||
});
|
|
||||||
self.right = self.right.right;
|
|
||||||
return self.transform(compressor);
|
|
||||||
}
|
|
||||||
return try_evaluate(compressor, self);
|
return try_evaluate(compressor, self);
|
||||||
|
|
||||||
function align(ref, op) {
|
function align(ref, op) {
|
||||||
@@ -7071,7 +7114,7 @@ merge(Compressor.prototype, {
|
|||||||
return reachable;
|
return reachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &");
|
var ASSIGN_OPS = makePredicate("+ - * / % >> << >>> | ^ &");
|
||||||
var ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &");
|
var ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &");
|
||||||
OPT(AST_Assign, function(self, compressor) {
|
OPT(AST_Assign, function(self, compressor) {
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
@@ -7115,7 +7158,8 @@ merge(Compressor.prototype, {
|
|||||||
|| parent instanceof AST_UnaryPrefix);
|
|| parent instanceof AST_UnaryPrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self = self.lift_sequences(compressor);
|
var seq = self.lift_sequences(compressor);
|
||||||
|
if (seq !== self) return seq;
|
||||||
if (!compressor.option("assignments")) return self;
|
if (!compressor.option("assignments")) return self;
|
||||||
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||||
// x = expr1 OP expr2
|
// x = expr1 OP expr2
|
||||||
@@ -7180,23 +7224,24 @@ merge(Compressor.prototype, {
|
|||||||
expressions.push(self);
|
expressions.push(self);
|
||||||
return make_sequence(self, expressions);
|
return make_sequence(self, expressions);
|
||||||
}
|
}
|
||||||
var cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
|
var condition = self.condition.is_truthy() || self.condition.evaluate(compressor);
|
||||||
if (!cond) {
|
if (!condition) {
|
||||||
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.start);
|
||||||
return make_sequence(self, [ self.condition, self.alternative ]).optimize(compressor);
|
return make_sequence(self, [ self.condition, self.alternative ]).optimize(compressor);
|
||||||
} else if (!(cond instanceof AST_Node)) {
|
} else if (!(condition instanceof AST_Node)) {
|
||||||
AST_Node.warn("Condition always true [{file}:{line},{col}]", self.start);
|
AST_Node.warn("Condition always true [{file}:{line},{col}]", self.start);
|
||||||
return make_sequence(self, [ self.condition, self.consequent ]).optimize(compressor);
|
return make_sequence(self, [ self.condition, self.consequent ]).optimize(compressor);
|
||||||
}
|
}
|
||||||
var negated = cond.negate(compressor, first_in_statement(compressor));
|
var negated = condition.negate(compressor, first_in_statement(compressor));
|
||||||
if (best_of(compressor, cond, negated) === negated) {
|
if (best_of(compressor, condition, negated) === negated) {
|
||||||
self = make_node(AST_Conditional, self, {
|
self = make_node(AST_Conditional, self, {
|
||||||
condition: negated,
|
condition: negated,
|
||||||
consequent: self.alternative,
|
consequent: self.alternative,
|
||||||
alternative: self.consequent
|
alternative: self.consequent
|
||||||
});
|
});
|
||||||
|
negated = condition;
|
||||||
|
condition = self.condition;
|
||||||
}
|
}
|
||||||
var condition = self.condition;
|
|
||||||
var consequent = self.consequent;
|
var consequent = self.consequent;
|
||||||
var alternative = self.alternative;
|
var alternative = self.alternative;
|
||||||
// x ? x : y => x || y
|
// x ? x : y => x || y
|
||||||
@@ -7284,6 +7329,19 @@ merge(Compressor.prototype, {
|
|||||||
alternative: alternative
|
alternative: alternative
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// x ? (y ? a : b) : a => !x || y ? a : b
|
||||||
|
if (consequent instanceof AST_Conditional
|
||||||
|
&& consequent.consequent.equivalent_to(alternative)) {
|
||||||
|
return make_node(AST_Conditional, self, {
|
||||||
|
condition: make_node(AST_Binary, self, {
|
||||||
|
left: negated,
|
||||||
|
operator: "||",
|
||||||
|
right: consequent.condition
|
||||||
|
}),
|
||||||
|
consequent: alternative,
|
||||||
|
alternative: consequent.alternative
|
||||||
|
});
|
||||||
|
}
|
||||||
// x ? a : (y ? a : b) => x || y ? a : b
|
// x ? a : (y ? a : b) => x || y ? a : b
|
||||||
if (alternative instanceof AST_Conditional
|
if (alternative instanceof AST_Conditional
|
||||||
&& consequent.equivalent_to(alternative.consequent)) {
|
&& consequent.equivalent_to(alternative.consequent)) {
|
||||||
@@ -7297,7 +7355,20 @@ merge(Compressor.prototype, {
|
|||||||
alternative: alternative.alternative
|
alternative: alternative.alternative
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x ? (y, w) : (z, w) => x ? y : z, w
|
// x ? b : (y ? a : b) => !x && y ? a : b
|
||||||
|
if (alternative instanceof AST_Conditional
|
||||||
|
&& consequent.equivalent_to(alternative.alternative)) {
|
||||||
|
return make_node(AST_Conditional, self, {
|
||||||
|
condition: make_node(AST_Binary, self, {
|
||||||
|
left: negated,
|
||||||
|
operator: "&&",
|
||||||
|
right: alternative.condition
|
||||||
|
}),
|
||||||
|
consequent: alternative.consequent,
|
||||||
|
alternative: consequent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// x ? (a, c) : (b, c) => x ? a : b, c
|
||||||
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
||||||
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
|
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
|
||||||
return make_sequence(self, [
|
return make_sequence(self, [
|
||||||
@@ -7309,7 +7380,21 @@ merge(Compressor.prototype, {
|
|||||||
consequent.tail_node()
|
consequent.tail_node()
|
||||||
]).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
// x ? y || z : z => x && y || z
|
// x ? y && a : a => (!x || y) && a
|
||||||
|
if (consequent instanceof AST_Binary
|
||||||
|
&& consequent.operator == "&&"
|
||||||
|
&& consequent.right.equivalent_to(alternative)) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: make_node(AST_Binary, self, {
|
||||||
|
operator: "||",
|
||||||
|
left: negated,
|
||||||
|
right: consequent.left
|
||||||
|
}),
|
||||||
|
right: alternative
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
// x ? y || a : a => x && y || a
|
||||||
if (consequent instanceof AST_Binary
|
if (consequent instanceof AST_Binary
|
||||||
&& consequent.operator == "||"
|
&& consequent.operator == "||"
|
||||||
&& consequent.right.equivalent_to(alternative)) {
|
&& consequent.right.equivalent_to(alternative)) {
|
||||||
@@ -7323,6 +7408,34 @@ merge(Compressor.prototype, {
|
|||||||
right: alternative
|
right: alternative
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
|
// x ? a : y && a => (x || y) && a
|
||||||
|
if (alternative instanceof AST_Binary
|
||||||
|
&& alternative.operator == "&&"
|
||||||
|
&& alternative.right.equivalent_to(consequent)) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: make_node(AST_Binary, self, {
|
||||||
|
operator: "||",
|
||||||
|
left: condition,
|
||||||
|
right: alternative.left
|
||||||
|
}),
|
||||||
|
right: consequent
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
// x ? a : y || a => !x && y || a
|
||||||
|
if (alternative instanceof AST_Binary
|
||||||
|
&& alternative.operator == "||"
|
||||||
|
&& alternative.right.equivalent_to(consequent)) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "||",
|
||||||
|
left: make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: negated,
|
||||||
|
right: alternative.left
|
||||||
|
}),
|
||||||
|
right: consequent
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
||||||
if (is_true(consequent)) {
|
if (is_true(consequent)) {
|
||||||
if (is_false(alternative)) {
|
if (is_false(alternative)) {
|
||||||
@@ -7474,6 +7587,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OPT(AST_Sub, function(self, compressor) {
|
OPT(AST_Sub, function(self, compressor) {
|
||||||
|
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
if (compressor.option("properties")) {
|
if (compressor.option("properties")) {
|
||||||
@@ -7638,6 +7755,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor) {
|
OPT(AST_Dot, function(self, compressor) {
|
||||||
|
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
if (self.property == "arguments" || self.property == "caller") {
|
if (self.property == "arguments" || self.property == "caller") {
|
||||||
AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
|
AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
|
||||||
prop: self.property,
|
prop: self.property,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.7.6",
|
"version": "3.7.7",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ holes_and_undefined: {
|
|||||||
constant_join: {
|
constant_join: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -65,6 +66,7 @@ constant_join: {
|
|||||||
constant_join_2: {
|
constant_join_2: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -94,9 +96,11 @@ constant_join_2: {
|
|||||||
constant_join_3: {
|
constant_join_3: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
var foo, bar, baz;
|
||||||
var a = [ null ].join();
|
var a = [ null ].join();
|
||||||
var b = [ , ].join();
|
var b = [ , ].join();
|
||||||
var c = [ , 1, , 3 ].join();
|
var c = [ , 1, , 3 ].join();
|
||||||
@@ -111,6 +115,7 @@ constant_join_3: {
|
|||||||
var l = [ foo, bar + "baz" ].join("");
|
var l = [ foo, bar + "baz" ].join("");
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var foo, bar, baz;
|
||||||
var a = "";
|
var a = "";
|
||||||
var b = "";
|
var b = "";
|
||||||
var c = ",1,,3";
|
var c = ",1,,3";
|
||||||
|
|||||||
@@ -131,3 +131,25 @@ issue_3658: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3690: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return function() {
|
||||||
|
return a = [ this ];
|
||||||
|
}() ? "PASS" : "FAIL";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return function() {
|
||||||
|
return 1;
|
||||||
|
}() ? "PASS" : "FAIL";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -7491,3 +7491,277 @@ issue_3671: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
call_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
a = console;
|
||||||
|
(function() {})();
|
||||||
|
a.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
(function() {})();
|
||||||
|
(a = console).log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_1_symbol: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {}
|
||||||
|
a = console;
|
||||||
|
f();
|
||||||
|
a.log(typeof f);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {}
|
||||||
|
f();
|
||||||
|
(a = console).log(typeof f);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
a = console;
|
||||||
|
(function() {
|
||||||
|
return 42;
|
||||||
|
console.log("FAIL");
|
||||||
|
})();
|
||||||
|
a.log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
(function() {
|
||||||
|
return 42;
|
||||||
|
console.log("FAIL");
|
||||||
|
})();
|
||||||
|
(a = console).log("PASS");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_2_symbol: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {
|
||||||
|
return 42;
|
||||||
|
console.log("FAIL");
|
||||||
|
}
|
||||||
|
a = console;
|
||||||
|
f();
|
||||||
|
a.log(typeof f);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {
|
||||||
|
return 42;
|
||||||
|
console.log("FAIL");
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
(a = console).log(typeof f);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
a = console;
|
||||||
|
(function() {
|
||||||
|
a = {
|
||||||
|
log: function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
a.log("FAIL");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
a = console;
|
||||||
|
(function() {
|
||||||
|
a = {
|
||||||
|
log: function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
a.log("FAIL");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_3_symbol: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {
|
||||||
|
a = {
|
||||||
|
log: function() {
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a = console;
|
||||||
|
f();
|
||||||
|
a.log("FAIL");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
function f() {
|
||||||
|
a = {
|
||||||
|
log: function() {
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a = console;
|
||||||
|
f();
|
||||||
|
a.log("FAIL");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3698_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var log = console.log;
|
||||||
|
var a, b = 0, c = 0;
|
||||||
|
(function() {
|
||||||
|
a = b;
|
||||||
|
})(b++, (b++, c++));
|
||||||
|
log(a, b, c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var log = console.log;
|
||||||
|
var a, b = 0, c = 0;
|
||||||
|
(function() {
|
||||||
|
a = b;
|
||||||
|
})(b++, (b++, c++));
|
||||||
|
log(a, b, c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3698_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var log = console.log;
|
||||||
|
var a, b = 0, c = 0, d = 1;
|
||||||
|
(function f() {
|
||||||
|
a = b;
|
||||||
|
d-- && f();
|
||||||
|
})(b++, (b++, c++));
|
||||||
|
log(a, b, c, d);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var log = console.log;
|
||||||
|
var a, b = 0, c = 0, d = 1;
|
||||||
|
(function f() {
|
||||||
|
a = b;
|
||||||
|
d-- && f();
|
||||||
|
})(b++, (b++, c++));
|
||||||
|
log(a, b, c, d);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 2 1 -1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3698_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
(function f(c) {
|
||||||
|
{
|
||||||
|
b++;
|
||||||
|
var bar_1 = (b = 1 + b, c = 0);
|
||||||
|
a-- && f();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
(function f(c) {
|
||||||
|
var bar_1 = (b = 1 + ++b, c = 0);
|
||||||
|
a-- && f();
|
||||||
|
})();
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3700: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
(function() {
|
||||||
|
throw 0;
|
||||||
|
})();
|
||||||
|
a = 1 + a;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
(function() {
|
||||||
|
throw 0;
|
||||||
|
})();
|
||||||
|
a = 1 + a;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ concat_1: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_2: {
|
concat_2: {
|
||||||
options = {}
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
1 + (2 + 3),
|
1 + (2 + 3),
|
||||||
@@ -55,7 +57,9 @@ concat_2: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_3: {
|
concat_3: {
|
||||||
options = {}
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
1 + 2 + (3 + 4 + 5),
|
1 + 2 + (3 + 4 + 5),
|
||||||
@@ -84,7 +88,9 @@ concat_3: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_4: {
|
concat_4: {
|
||||||
options = {}
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
1 + "2" + (3 + 4 + 5),
|
1 + "2" + (3 + 4 + 5),
|
||||||
@@ -113,7 +119,9 @@ concat_4: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_5: {
|
concat_5: {
|
||||||
options = {}
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
"1" + 2 + (3 + 4 + 5),
|
"1" + 2 + (3 + 4 + 5),
|
||||||
@@ -142,7 +150,9 @@ concat_5: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_6: {
|
concat_6: {
|
||||||
options = {}
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
"1" + "2" + (3 + 4 + 5),
|
"1" + "2" + (3 + 4 + 5),
|
||||||
@@ -171,6 +181,9 @@ concat_6: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_7: {
|
concat_7: {
|
||||||
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
"" + 1,
|
"" + 1,
|
||||||
@@ -197,6 +210,9 @@ concat_7: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
concat_8: {
|
concat_8: {
|
||||||
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
1 + "",
|
1 + "",
|
||||||
@@ -221,3 +237,20 @@ concat_8: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3689: {
|
||||||
|
options = {
|
||||||
|
strings: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a + ("" + (a[0] = 0));
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a + ("" + (a[0] = 0));
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect_stdout: "00"
|
||||||
|
}
|
||||||
|
|||||||
@@ -294,6 +294,45 @@ cond_5: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cond_6: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x ? a : b;
|
||||||
|
x ? a : a;
|
||||||
|
|
||||||
|
x ? y ? a : b : c;
|
||||||
|
x ? y ? a : a : b;
|
||||||
|
x ? y ? a : b : b;
|
||||||
|
x ? y ? a : b : a;
|
||||||
|
x ? y ? a : a : a;
|
||||||
|
|
||||||
|
x ? a : y ? b : c;
|
||||||
|
x ? a : y ? a : b;
|
||||||
|
x ? a : y ? b : b;
|
||||||
|
x ? a : y ? b : a;
|
||||||
|
x ? a : y ? a : a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x ? a : b;
|
||||||
|
x, a;
|
||||||
|
|
||||||
|
x ? y ? a : b : c;
|
||||||
|
x ? (y, a) : b;
|
||||||
|
x && y ? a : b;
|
||||||
|
!x || y ? a : b;
|
||||||
|
x && y, a;
|
||||||
|
|
||||||
|
x ? a : y ? b : c;
|
||||||
|
x || y ? a : b;
|
||||||
|
x ? a : (y, b);
|
||||||
|
!x && y ? b : a;
|
||||||
|
!x && y, a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cond_7: {
|
cond_7: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -726,6 +765,24 @@ cond_11: {
|
|||||||
expect_stdout: "foo bar"
|
expect_stdout: "foo bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cond_12: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x ? y && a : a;
|
||||||
|
x ? y || a : a;
|
||||||
|
x ? a : y && a;
|
||||||
|
x ? a : y || a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(!x || y) && a;
|
||||||
|
x && y || a;
|
||||||
|
(x || y) && a;
|
||||||
|
!x && y || a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ternary_boolean_consequent: {
|
ternary_boolean_consequent: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
|
|||||||
@@ -830,6 +830,7 @@ issue_3552: {
|
|||||||
unreachable_assign: {
|
unreachable_assign: {
|
||||||
options = {
|
options = {
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
|
strings: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(A = "P" + (A = "A" + (B = "S" + (A = B = "S"))), A, B);
|
console.log(A = "P" + (A = "A" + (B = "S" + (A = B = "S"))), A, B);
|
||||||
|
|||||||
@@ -2244,7 +2244,7 @@ issue_3076: {
|
|||||||
var c = "PASS";
|
var c = "PASS";
|
||||||
(function(b) {
|
(function(b) {
|
||||||
var n = 2;
|
var n = 2;
|
||||||
while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1).toString() && --n > 0);
|
while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1..toString()) && --n > 0);
|
||||||
var e;
|
var e;
|
||||||
})(2),
|
})(2),
|
||||||
console.log(c);
|
console.log(c);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ mangle_props: {
|
|||||||
obj[1/0],
|
obj[1/0],
|
||||||
obj["Infinity"],
|
obj["Infinity"],
|
||||||
obj[-1/0],
|
obj[-1/0],
|
||||||
obj[-1/0],
|
obj[-(1/0)],
|
||||||
obj["-Infinity"],
|
obj["-Infinity"],
|
||||||
obj[null],
|
obj[null],
|
||||||
obj["null"]
|
obj["null"]
|
||||||
|
|||||||
@@ -1,98 +1,111 @@
|
|||||||
issue_269_1: {
|
issue_269_1: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
f(
|
var x = {};
|
||||||
String(x),
|
console.log(
|
||||||
Number(x),
|
String(x),
|
||||||
Boolean(x),
|
Number(x),
|
||||||
|
Boolean(x),
|
||||||
|
|
||||||
String(),
|
String(),
|
||||||
Number(),
|
Number(),
|
||||||
Boolean()
|
Boolean()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
f(
|
var x = {};
|
||||||
x + '', +x, !!x,
|
console.log(
|
||||||
'', 0, false
|
x + "", +x, !!x,
|
||||||
);
|
"", 0, false
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_269_dangers: {
|
issue_269_dangers: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
f(
|
var x = {};
|
||||||
String(x, x),
|
console.log(
|
||||||
Number(x, x),
|
String(x, x),
|
||||||
Boolean(x, x)
|
Number(x, x),
|
||||||
);
|
Boolean(x, x)
|
||||||
}
|
);
|
||||||
expect: {
|
}
|
||||||
f(String(x, x), Number(x, x), Boolean(x, x));
|
expect: {
|
||||||
}
|
var x = {};
|
||||||
|
console.log(String(x, x), Number(x, x), Boolean(x, x));
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_269_in_scope: {
|
issue_269_in_scope: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var String, Number, Boolean;
|
var String, Number, Boolean;
|
||||||
f(
|
var x = {};
|
||||||
String(x),
|
console.log(
|
||||||
Number(x, x),
|
String(x),
|
||||||
Boolean(x)
|
Number(x, x),
|
||||||
);
|
Boolean(x)
|
||||||
}
|
);
|
||||||
expect: {
|
}
|
||||||
var String, Number, Boolean;
|
expect: {
|
||||||
f(String(x), Number(x, x), Boolean(x));
|
var String, Number, Boolean;
|
||||||
}
|
var x = {};
|
||||||
|
console.log(String(x), Number(x, x), Boolean(x));
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
strings_concat: {
|
strings_concat: {
|
||||||
options = {
|
options = {
|
||||||
|
strings: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
f(
|
var x = {};
|
||||||
String(x + 'str'),
|
console.log(
|
||||||
String('str' + x)
|
String(x + "str"),
|
||||||
);
|
String("str" + x)
|
||||||
}
|
);
|
||||||
expect: {
|
}
|
||||||
f(
|
expect: {
|
||||||
x + 'str',
|
var x = {};
|
||||||
'str' + x
|
console.log(
|
||||||
);
|
x + "str",
|
||||||
}
|
"str" + x
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
regexp: {
|
regexp: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
RegExp("foo");
|
RegExp("foo");
|
||||||
RegExp("bar", "ig");
|
RegExp("bar", "ig");
|
||||||
RegExp(foo);
|
RegExp(foo);
|
||||||
RegExp("bar", ig);
|
RegExp("bar", ig);
|
||||||
RegExp("should", "fail");
|
RegExp("should", "fail");
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
/foo/;
|
/foo/;
|
||||||
/bar/ig;
|
/bar/ig;
|
||||||
RegExp(foo);
|
RegExp(foo);
|
||||||
RegExp("bar", ig);
|
RegExp("bar", ig);
|
||||||
RegExp("should", "fail");
|
RegExp("should", "fail");
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,2]',
|
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,8]',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -669,6 +669,9 @@ issue_1710: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unary_binary_parenthesis: {
|
unary_binary_parenthesis: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ];
|
var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ];
|
||||||
v.forEach(function(x) {
|
v.forEach(function(x) {
|
||||||
@@ -1233,3 +1236,18 @@ issue_3684: {
|
|||||||
"Infinity",
|
"Infinity",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3695: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [];
|
||||||
|
console.log(+(a * (a[0] = false)));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = [];
|
||||||
|
console.log(+(a * (a[0] = false)));
|
||||||
|
}
|
||||||
|
expect_stdout: "NaN"
|
||||||
|
}
|
||||||
|
|||||||
@@ -910,15 +910,23 @@ call: {
|
|||||||
console.log(this === b ? "bar" : "baz");
|
console.log(this === b ? "bar" : "baz");
|
||||||
};
|
};
|
||||||
(a, b)();
|
(a, b)();
|
||||||
|
(a, b).c();
|
||||||
(a, b.c)();
|
(a, b.c)();
|
||||||
|
(a, b)["c"]();
|
||||||
|
(a, b["c"])();
|
||||||
(a, function() {
|
(a, function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
})();
|
})();
|
||||||
new (a, b)();
|
new (a, b)();
|
||||||
|
new (a, b).c();
|
||||||
new (a, b.c)();
|
new (a, b.c)();
|
||||||
|
new (a, b)["c"]();
|
||||||
|
new (a, b["c"])();
|
||||||
new (a, function() {
|
new (a, function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
})();
|
})();
|
||||||
|
console.log(typeof (a, b).c);
|
||||||
|
console.log(typeof (a, b)["c"]);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = function() {
|
var a = function() {
|
||||||
@@ -931,23 +939,39 @@ call: {
|
|||||||
console.log(this === b ? "bar" : "baz");
|
console.log(this === b ? "bar" : "baz");
|
||||||
},
|
},
|
||||||
b(),
|
b(),
|
||||||
|
b.c(),
|
||||||
(a, b.c)(),
|
(a, b.c)(),
|
||||||
|
b["c"](),
|
||||||
|
(a, b["c"])(),
|
||||||
function() {
|
function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
}(),
|
}(),
|
||||||
new b(),
|
new b(),
|
||||||
new b.c(),
|
new b.c(),
|
||||||
|
new b.c(),
|
||||||
|
new b["c"](),
|
||||||
|
new b["c"](),
|
||||||
new function() {
|
new function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
}();
|
}(),
|
||||||
|
console.log((a, typeof b.c)),
|
||||||
|
console.log((a, typeof b["c"]));
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"foo",
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"baz",
|
||||||
|
"bar",
|
||||||
"baz",
|
"baz",
|
||||||
"true",
|
"true",
|
||||||
"foo",
|
"foo",
|
||||||
"baz",
|
"baz",
|
||||||
|
"baz",
|
||||||
|
"baz",
|
||||||
|
"baz",
|
||||||
"false",
|
"false",
|
||||||
|
"function",
|
||||||
|
"function",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user