Compare commits

...

9 Commits

Author SHA1 Message Date
Alex Lam S.L
ea999b0e92 v3.4.9 2018-08-31 04:28:21 +00:00
Alex Lam S.L
ce7e220de4 fix corner case in conditionals (#3244) 2018-08-30 15:59:05 +08:00
Alex Lam S.L
2bdaca10ae enhance conditionals (#3243) 2018-08-30 01:06:34 +08:00
Alex Lam S.L
aa0029204e fix corner case in reduce_vars (#3241)
fixes #3240
2018-08-29 22:14:25 +08:00
Alex Lam S.L
f352bcec3a fix corner case in collapse_vars (#3239)
fixes #3238
2018-08-29 11:34:34 +08:00
Alex Lam S.L
08514030f4 v3.4.8 2018-08-23 15:27:34 +08:00
Alex Lam S.L
694ca5d045 fix corner case in unused (#3234)
fixes #3233
2018-08-23 06:03:39 +08:00
Alex Lam S.L
57fb58b263 enhance if_return (#3232) 2018-08-21 18:34:16 +08:00
alexlamsl
18c1c9b38a update dependencies
- commander@2.17.1
2018-08-14 17:06:09 +08:00
8 changed files with 750 additions and 119 deletions

View File

@@ -450,8 +450,7 @@ merge(Compressor.prototype, {
return value instanceof AST_Node && def.fixed.parent_scope === scope; return value instanceof AST_Node && def.fixed.parent_scope === scope;
} }
return all(def.orig, function(sym) { return all(def.orig, function(sym) {
return !(sym instanceof AST_SymbolDefun return !(sym instanceof AST_SymbolDefun || sym instanceof AST_SymbolLambda);
|| sym instanceof AST_SymbolLambda);
}); });
} }
@@ -1482,14 +1481,26 @@ merge(Compressor.prototype, {
} }
function get_rhs(expr) { function get_rhs(expr) {
if (!(candidate instanceof AST_Assign && candidate.operator == "=")) return; return candidate instanceof AST_Assign && candidate.operator == "=" && candidate.right;
return candidate.right;
} }
function get_rvalue(expr) { function get_rvalue(expr) {
return expr[expr instanceof AST_Assign ? "right" : "value"]; return expr[expr instanceof AST_Assign ? "right" : "value"];
} }
function invariant(expr) {
if (expr instanceof AST_Array) return false;
if (expr instanceof AST_Binary && lazy_op[expr.operator]) {
return invariant(expr.left) && invariant(expr.right);
}
if (expr instanceof AST_Call) return false;
if (expr instanceof AST_Conditional) {
return invariant(expr.consequent) && invariant(expr.alternative);
}
if (expr instanceof AST_Object) return false;
return !expr.has_side_effects(compressor);
}
function foldable(expr) { function foldable(expr) {
if (expr instanceof AST_SymbolRef) { if (expr instanceof AST_SymbolRef) {
var value = expr.evaluate(compressor); var value = expr.evaluate(compressor);
@@ -1502,7 +1513,7 @@ merge(Compressor.prototype, {
return rhs_fuzzy_match(expr.evaluate(compressor), rhs_exact_match); return rhs_fuzzy_match(expr.evaluate(compressor), rhs_exact_match);
} }
if (!(lhs instanceof AST_SymbolRef)) return false; if (!(lhs instanceof AST_SymbolRef)) return false;
if (expr.has_side_effects(compressor)) return false; if (!invariant(expr)) return false;
var circular; var circular;
var def = lhs.definition(); var def = lhs.definition();
expr.walk(new TreeWalker(function(node) { expr.walk(new TreeWalker(function(node) {
@@ -1699,6 +1710,19 @@ merge(Compressor.prototype, {
continue; continue;
} }
if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
var negated = stat.condition.negate(compressor);
if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
CHANGED = true;
stat = stat.clone();
stat.condition = negated;
statements[j] = stat.body;
stat.body = next;
statements[i] = stat.transform(compressor);
continue;
}
}
var ab = aborts(stat.alternative); var ab = aborts(stat.alternative);
if (can_merge_flow(ab)) { if (can_merge_flow(ab)) {
if (ab.label) { if (ab.label) {
@@ -2968,19 +2992,21 @@ merge(Compressor.prototype, {
// determine if expression has side effects // determine if expression has side effects
(function(def) { (function(def) {
def(AST_Node, return_true);
def(AST_EmptyStatement, return_false);
def(AST_Constant, return_false);
def(AST_This, return_false);
function any(list, compressor) { function any(list, compressor) {
for (var i = list.length; --i >= 0;) for (var i = list.length; --i >= 0;)
if (list[i].has_side_effects(compressor)) if (list[i].has_side_effects(compressor))
return true; return true;
return false; return false;
} }
def(AST_Node, return_true);
def(AST_Array, function(compressor) {
return any(this.elements, compressor);
});
def(AST_Assign, return_true);
def(AST_Binary, function(compressor) {
return this.left.has_side_effects(compressor)
|| this.right.has_side_effects(compressor);
});
def(AST_Block, function(compressor) { def(AST_Block, function(compressor) {
return any(this.body, compressor); return any(this.body, compressor);
}); });
@@ -2992,19 +3018,24 @@ merge(Compressor.prototype, {
} }
return any(this.args, compressor); return any(this.args, compressor);
}); });
def(AST_Switch, function(compressor) {
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
def(AST_Case, function(compressor) { def(AST_Case, function(compressor) {
return this.expression.has_side_effects(compressor) return this.expression.has_side_effects(compressor)
|| any(this.body, compressor); || any(this.body, compressor);
}); });
def(AST_Try, function(compressor) { def(AST_Conditional, function(compressor) {
return any(this.body, compressor) return this.condition.has_side_effects(compressor)
|| this.bcatch && this.bcatch.has_side_effects(compressor) || this.consequent.has_side_effects(compressor)
|| this.bfinally && this.bfinally.has_side_effects(compressor); || this.alternative.has_side_effects(compressor);
}); });
def(AST_Constant, return_false);
def(AST_Definitions, function(compressor) {
return any(this.definitions, compressor);
});
def(AST_Dot, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor);
});
def(AST_EmptyStatement, return_false);
def(AST_If, function(compressor) { def(AST_If, function(compressor) {
return this.condition.has_side_effects(compressor) return this.condition.has_side_effects(compressor)
|| this.body && this.body.has_side_effects(compressor) || this.body && this.body.has_side_effects(compressor)
@@ -3013,41 +3044,13 @@ merge(Compressor.prototype, {
def(AST_LabeledStatement, function(compressor) { def(AST_LabeledStatement, function(compressor) {
return this.body.has_side_effects(compressor); return this.body.has_side_effects(compressor);
}); });
def(AST_SimpleStatement, function(compressor) {
return this.body.has_side_effects(compressor);
});
def(AST_Lambda, return_false); def(AST_Lambda, return_false);
def(AST_Binary, function(compressor) {
return this.left.has_side_effects(compressor)
|| this.right.has_side_effects(compressor);
});
def(AST_Assign, return_true);
def(AST_Conditional, function(compressor) {
return this.condition.has_side_effects(compressor)
|| this.consequent.has_side_effects(compressor)
|| this.alternative.has_side_effects(compressor);
});
def(AST_Unary, function(compressor) {
return unary_side_effects[this.operator]
|| this.expression.has_side_effects(compressor);
});
def(AST_SymbolRef, function(compressor) {
return !this.is_declared(compressor);
});
def(AST_SymbolDeclaration, return_false);
def(AST_Object, function(compressor) { def(AST_Object, function(compressor) {
return any(this.properties, compressor); return any(this.properties, compressor);
}); });
def(AST_ObjectProperty, function(compressor) { def(AST_ObjectProperty, function(compressor) {
return this.value.has_side_effects(compressor); return this.value.has_side_effects(compressor);
}); });
def(AST_Array, function(compressor) {
return any(this.elements, compressor);
});
def(AST_Dot, function(compressor) {
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor);
});
def(AST_Sub, function(compressor) { def(AST_Sub, function(compressor) {
return this.expression.may_throw_on_access(compressor) return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor) || this.expression.has_side_effects(compressor)
@@ -3056,8 +3059,26 @@ merge(Compressor.prototype, {
def(AST_Sequence, function(compressor) { def(AST_Sequence, function(compressor) {
return any(this.expressions, compressor); return any(this.expressions, compressor);
}); });
def(AST_Definitions, function(compressor) { def(AST_SimpleStatement, function(compressor) {
return any(this.definitions, compressor); return this.body.has_side_effects(compressor);
});
def(AST_Switch, function(compressor) {
return this.expression.has_side_effects(compressor)
|| any(this.body, compressor);
});
def(AST_SymbolDeclaration, return_false);
def(AST_SymbolRef, function(compressor) {
return !this.is_declared(compressor);
});
def(AST_This, return_false);
def(AST_Try, function(compressor) {
return any(this.body, compressor)
|| this.bcatch && this.bcatch.has_side_effects(compressor)
|| this.bfinally && this.bfinally.has_side_effects(compressor);
});
def(AST_Unary, function(compressor) {
return unary_side_effects[this.operator]
|| this.expression.has_side_effects(compressor);
}); });
def(AST_VarDef, function(compressor) { def(AST_VarDef, function(compressor) {
return this.value; return this.value;
@@ -3316,13 +3337,14 @@ merge(Compressor.prototype, {
} else if (node instanceof AST_Unary && node.write_only) { } else if (node instanceof AST_Unary && node.write_only) {
sym = node.expression; sym = node.expression;
} }
if (/strict/.test(compressor.option("pure_getters"))) { if (!/strict/.test(compressor.option("pure_getters"))) return sym instanceof AST_SymbolRef && sym;
while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) { while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) {
if (sym instanceof AST_Sub) props.unshift(sym.property); if (sym instanceof AST_Sub) props.unshift(sym.property);
sym = sym.expression; sym = sym.expression;
}
} }
return sym; return sym instanceof AST_SymbolRef && all(sym.definition().orig, function(sym) {
return !(sym instanceof AST_SymbolLambda);
}) && sym;
}; };
var in_use = []; var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
@@ -3417,7 +3439,7 @@ merge(Compressor.prototype, {
var parent = tt.parent(); var parent = tt.parent();
if (drop_vars) { if (drop_vars) {
var props = [], sym = assign_as_unused(node, props); var props = [], sym = assign_as_unused(node, props);
if (sym instanceof AST_SymbolRef) { if (sym) {
var def = sym.definition(); var def = sym.definition();
var in_use = def.id in in_use_ids; var in_use = def.id in in_use_ids;
var value = null; var value = null;
@@ -3616,8 +3638,7 @@ merge(Compressor.prototype, {
function scan_ref_scoped(node, descend) { function scan_ref_scoped(node, descend) {
var node_def, props = [], sym = assign_as_unused(node, props); var node_def, props = [], sym = assign_as_unused(node, props);
if (sym instanceof AST_SymbolRef if (sym && self.variables.get(sym.name) === (node_def = sym.definition())) {
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
props.forEach(function(prop) { props.forEach(function(prop) {
prop.walk(tw); prop.walk(tw);
}); });
@@ -5730,38 +5751,34 @@ merge(Compressor.prototype, {
} }
var parent = compressor.parent(); var parent = compressor.parent();
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) { if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
var d = self.definition(); var def = self.definition();
var fixed = self.fixed_value(); var fixed = self.fixed_value();
var single_use = d.single_use var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
&& !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
if (single_use && fixed instanceof AST_Lambda) { if (single_use && fixed instanceof AST_Lambda) {
if (d.scope !== self.scope if (def.scope !== self.scope
&& (!compressor.option("reduce_funcs") && (!compressor.option("reduce_funcs") || def.escaped == 1 || fixed.inlined)) {
|| d.escaped == 1
|| fixed.inlined)) {
single_use = false; single_use = false;
} else if (recursive_ref(compressor, d)) { } else if (recursive_ref(compressor, def)) {
single_use = false; single_use = false;
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) { } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
single_use = fixed.is_constant_expression(self.scope); single_use = fixed.is_constant_expression(self.scope);
if (single_use == "f") { if (single_use == "f") {
var scope = self.scope; var scope = self.scope;
do { do if (scope instanceof AST_Defun || scope instanceof AST_Function) {
if (scope instanceof AST_Defun || scope instanceof AST_Function) { scope.inlined = true;
scope.inlined = true;
}
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
} }
} }
} }
if (single_use && fixed) { if (single_use && fixed) {
def.single_use = false;
if (fixed instanceof AST_Defun) { if (fixed instanceof AST_Defun) {
fixed._squeezed = true; fixed._squeezed = true;
fixed = make_node(AST_Function, fixed, fixed); fixed = make_node(AST_Function, fixed, fixed);
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name); fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
} }
var value; var value;
if (d.recursive_refs > 0) { if (def.recursive_refs > 0) {
value = fixed.clone(true); value = fixed.clone(true);
var defun_def = value.name.definition(); var defun_def = value.name.definition();
var lambda_def = value.variables.get(value.name.name); var lambda_def = value.variables.get(value.name.name);
@@ -5773,9 +5790,13 @@ merge(Compressor.prototype, {
lambda_def = value.def_function(name); lambda_def = value.def_function(name);
} }
value.walk(new TreeWalker(function(node) { value.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolRef && node.definition() === defun_def) { if (!(node instanceof AST_SymbolRef)) return;
var def = node.definition();
if (def === defun_def) {
node.thedef = lambda_def; node.thedef = lambda_def;
lambda_def.references.push(node); lambda_def.references.push(node);
} else {
def.single_use = false;
} }
})); }));
} else { } else {
@@ -5784,13 +5805,12 @@ merge(Compressor.prototype, {
} }
return value; return value;
} }
if (fixed && d.should_replace === undefined) { if (fixed && def.should_replace === undefined) {
var init; var init;
if (fixed instanceof AST_This) { if (fixed instanceof AST_This) {
if (!(d.orig[0] instanceof AST_SymbolFunarg) if (!(def.orig[0] instanceof AST_SymbolFunarg) && all(def.references, function(ref) {
&& all(d.references, function(ref) { return def.scope === ref.scope;
return d.scope === ref.scope; })) {
})) {
init = fixed; init = fixed;
} }
} else { } else {
@@ -5814,18 +5834,18 @@ merge(Compressor.prototype, {
return result === init || result === fixed ? result.clone(true) : result; return result === init || result === fixed ? result.clone(true) : result;
}; };
} }
var name_length = d.name.length; var name_length = def.name.length;
var overhead = 0; var overhead = 0;
if (compressor.option("unused") && !compressor.exposed(d)) { if (compressor.option("unused") && !compressor.exposed(def)) {
overhead = (name_length + 2 + value_length) / (d.references.length - d.assignments); overhead = (name_length + 2 + value_length) / (def.references.length - def.assignments);
} }
d.should_replace = value_length <= name_length + overhead ? fn : false; def.should_replace = value_length <= name_length + overhead ? fn : false;
} else { } else {
d.should_replace = false; def.should_replace = false;
} }
} }
if (d.should_replace) { if (def.should_replace) {
return d.should_replace(); return def.should_replace();
} }
} }
return self; return self;
@@ -6027,22 +6047,26 @@ merge(Compressor.prototype, {
// | // |
// v // v
// exp = foo ? something : something_else; // exp = foo ? something : something_else;
if (consequent instanceof AST_Assign var seq_tail = consequent.tail_node();
&& alternative instanceof AST_Assign if (seq_tail instanceof AST_Assign) {
&& consequent.operator == alternative.operator var is_eq = seq_tail.operator == "=";
&& consequent.left.equivalent_to(alternative.left) var alt_tail = is_eq ? alternative.tail_node() : alternative;
&& (!self.condition.has_side_effects(compressor) if ((is_eq || consequent instanceof AST_Assign)
|| consequent.operator == "=" && alt_tail instanceof AST_Assign
&& !consequent.left.has_side_effects(compressor))) { && seq_tail.operator == alt_tail.operator
return make_node(AST_Assign, self, { && seq_tail.left.equivalent_to(alt_tail.left)
operator: consequent.operator, && (!condition.has_side_effects(compressor)
left: consequent.left, || is_eq && !seq_tail.left.has_side_effects(compressor))) {
right: make_node(AST_Conditional, self, { return make_node(AST_Assign, self, {
condition: self.condition, operator: seq_tail.operator,
consequent: consequent.right, left: seq_tail.left,
alternative: alternative.right right: make_node(AST_Conditional, self, {
}) condition: condition,
}); consequent: pop_lhs(consequent),
alternative: pop_lhs(alternative)
})
});
}
} }
// x ? y(a) : y(b) --> y(x ? a : b) // x ? y(a) : y(b) --> y(x ? a : b)
var arg_index; var arg_index;
@@ -6051,12 +6075,12 @@ merge(Compressor.prototype, {
&& consequent.args.length > 0 && consequent.args.length > 0
&& consequent.args.length == alternative.args.length && consequent.args.length == alternative.args.length
&& consequent.expression.equivalent_to(alternative.expression) && consequent.expression.equivalent_to(alternative.expression)
&& !self.condition.has_side_effects(compressor) && !condition.has_side_effects(compressor)
&& !consequent.expression.has_side_effects(compressor) && !consequent.expression.has_side_effects(compressor)
&& typeof (arg_index = single_arg_diff()) == "number") { && typeof (arg_index = single_arg_diff()) == "number") {
var node = consequent.clone(); var node = consequent.clone();
node.args[arg_index] = make_node(AST_Conditional, self, { node.args[arg_index] = make_node(AST_Conditional, self, {
condition: self.condition, condition: condition,
consequent: consequent.args[arg_index], consequent: consequent.args[arg_index],
alternative: alternative.args[arg_index] alternative: alternative.args[arg_index]
}); });
@@ -6067,7 +6091,7 @@ merge(Compressor.prototype, {
&& consequent.alternative.equivalent_to(alternative)) { && consequent.alternative.equivalent_to(alternative)) {
return make_node(AST_Conditional, self, { return make_node(AST_Conditional, self, {
condition: make_node(AST_Binary, self, { condition: make_node(AST_Binary, self, {
left: self.condition, left: condition,
operator: "&&", operator: "&&",
right: consequent.condition right: consequent.condition
}), }),
@@ -6078,7 +6102,7 @@ merge(Compressor.prototype, {
// x ? y : y --> x, y // x ? y : y --> x, y
if (consequent.equivalent_to(alternative)) { if (consequent.equivalent_to(alternative)) {
return make_sequence(self, [ return make_sequence(self, [
self.condition, condition,
consequent consequent
]).optimize(compressor); ]).optimize(compressor);
} }
@@ -6087,7 +6111,7 @@ merge(Compressor.prototype, {
&& consequent.tail_node().equivalent_to(alternative.tail_node())) { && consequent.tail_node().equivalent_to(alternative.tail_node())) {
return make_sequence(self, [ return make_sequence(self, [
make_node(AST_Conditional, self, { make_node(AST_Conditional, self, {
condition: self.condition, condition: condition,
consequent: pop_seq(consequent), consequent: pop_seq(consequent),
alternative: pop_seq(alternative) alternative: pop_seq(alternative)
}), }),
@@ -6102,7 +6126,7 @@ merge(Compressor.prototype, {
operator: "||", operator: "||",
left: make_node(AST_Binary, self, { left: make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: self.condition, left: condition,
right: consequent.left right: consequent.left
}), }),
right: alternative right: alternative
@@ -6112,24 +6136,24 @@ merge(Compressor.prototype, {
if (is_true(self.consequent)) { if (is_true(self.consequent)) {
if (is_false(self.alternative)) { if (is_false(self.alternative)) {
// c ? true : false ---> !!c // c ? true : false ---> !!c
return booleanize(self.condition); return booleanize(condition);
} }
// c ? true : x ---> !!c || x // c ? true : x ---> !!c || x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "||", operator: "||",
left: booleanize(self.condition), left: booleanize(condition),
right: self.alternative right: self.alternative
}); });
} }
if (is_false(self.consequent)) { if (is_false(self.consequent)) {
if (is_true(self.alternative)) { if (is_true(self.alternative)) {
// c ? false : true ---> !c // c ? false : true ---> !c
return booleanize(self.condition.negate(compressor)); return booleanize(condition.negate(compressor));
} }
// c ? false : x ---> !c && x // c ? false : x ---> !c && x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: booleanize(self.condition.negate(compressor)), left: booleanize(condition.negate(compressor)),
right: self.alternative right: self.alternative
}); });
} }
@@ -6137,7 +6161,7 @@ merge(Compressor.prototype, {
// c ? x : true ---> !c || x // c ? x : true ---> !c || x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "||", operator: "||",
left: booleanize(self.condition.negate(compressor)), left: booleanize(condition.negate(compressor)),
right: self.consequent right: self.consequent
}); });
} }
@@ -6145,7 +6169,7 @@ merge(Compressor.prototype, {
// c ? x : false ---> !!c && x // c ? x : false ---> !!c && x
return make_node(AST_Binary, self, { return make_node(AST_Binary, self, {
operator: "&&", operator: "&&",
left: booleanize(self.condition), left: booleanize(condition),
right: self.consequent right: self.consequent
}); });
} }
@@ -6197,6 +6221,13 @@ merge(Compressor.prototype, {
} }
} }
function pop_lhs(node) {
if (!(node instanceof AST_Sequence)) return node.right;
var exprs = node.expressions.slice();
exprs.push(exprs.pop().right);
return make_sequence(node, exprs);
}
function pop_seq(node) { function pop_seq(node) {
if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, { if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, {
value: 0 value: 0

View File

@@ -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.4.7", "version": "3.4.9",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -23,7 +23,7 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.16.0", "commander": "~2.17.1",
"source-map": "~0.6.1" "source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -5827,3 +5827,183 @@ issue_3215_4: {
} }
expect_stdout: "number" expect_stdout: "number"
} }
issue_3238_1: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = Object.create(null);
c = Object.create(null);
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = Object.create(null);
c = Object.create(null);
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}
issue_3238_2: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = Error();
c = Error();
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = Error();
c = Error();
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}
issue_3238_3: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = new Date();
c = new Date();
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = new Date();
c = new Date();
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}
issue_3238_4: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = a && {};
c = a && {};
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = a && {};
c = a && {};
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}
issue_3238_5: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = a ? [] : 42;
c = a ? [] : 42;
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = a ? [] : 42;
c = a ? [] : 42;
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}
issue_3238_6: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
function f(a) {
var b, c;
if (a) {
b = a && 0 || [];
c = a && 0 || [];
}
return b === c;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
var b, c;
if (a) {
b = a && 0 || [];
c = a && 0 || [];
}
return b === c;
}
console.log(f(0), f(1));
}
expect_stdout: "true false"
}

View File

@@ -1292,3 +1292,95 @@ to_and_or: {
} }
expect_stdout: true expect_stdout: true
} }
cond_seq_assign_1: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a) {
var t;
if (a) {
t = "foo";
t = "bar";
} else {
console.log(t);
t = 42;
}
console.log(t);
}
f(f);
f();
}
expect: {
function f(a) {
var t;
t = a ? (t = "foo", "bar") : (console.log(t), 42),
console.log(t);
}
f(f),
f();
}
expect_stdout: [
"bar",
"undefined",
"42",
]
}
cond_seq_assign_2: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a) {
var t;
if (a) {
t = "foo";
a = "bar";
} else {
console.log(t);
t = 42;
}
console.log(t);
}
f(f);
f();
}
expect: {
function f(a) {
var t;
a ? (t = "foo", a = "bar") : (console.log(t), t = 42),
console.log(t);
}
f(f),
f();
}
expect_stdout: [
"foo",
"undefined",
"42",
]
}
cond_seq_assign_3: {
options = {
conditionals: true,
}
input: {
var c = 0;
if (this)
c = 1 + c, c = c + 1;
else
c = 1 + c, c = c + 1;
console.log(c);
}
expect: {
var c = 0;
this, c = 1 + c, c += 1;
console.log(c);
}
expect_stdout: "2"
}

View File

@@ -1982,3 +1982,26 @@ issue_3192: {
"foo bar", "foo bar",
] ]
} }
issue_3233: {
options = {
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a = function b() {
b.c = "PASS";
};
a();
console.log(a.c);
}
expect: {
var a = function b() {
b.c = "PASS";
};
a();
console.log(a.c);
}
expect_stdout: "PASS"
}

View File

@@ -396,3 +396,151 @@ if_if_return_return: {
} }
} }
} }
if_body_return_1: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}
if_body_return_2: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (0 + a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (0 + a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}
if_body_return_3: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (1 == a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (1 != a) return true;
if (b) throw new Error(c);
return 42;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}

View File

@@ -5354,6 +5354,7 @@ issue_2774: {
issue_2799_1: { issue_2799_1: {
options = { options = {
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
@@ -6429,3 +6430,159 @@ issue_3140_5: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_3240_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
f(1);
function f(a) {
console.log(a);
var g = function() {
f(a - 1);
};
if (a) g();
}
})();
}
expect: {
(function() {
(function f(a) {
console.log(a);
var g = function() {
f(a - 1);
};
if (a) g();
})(1);
})();
}
expect_stdout: [
"1",
"0",
]
}
issue_3240_2: {
options = {
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
f(1);
function f(a) {
console.log(a);
var g = function() {
f(a - 1);
};
if (a) g();
}
})();
}
expect: {
(function() {
(function f(a) {
console.log(a);
if (a) (function() {
f(a - 1);
})();
})(1);
})();
}
expect_stdout: [
"1",
"0",
]
}
issue_3240_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
f();
function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
var g = function() {
(b ? function() {} : function() {
f.a++;
f(1);
})();
};
g();
}
})();
}
expect: {
(function() {
(function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
var g = function() {
(b ? function() {} : function() {
f.a++;
f(1);
})();
};
g();
})();
})();
}
expect_stdout: [
"0",
"1",
]
}
issue_3240_4: {
options = {
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
f();
function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
var g = function() {
(b ? function() {} : function() {
f.a++;
f(1);
})();
};
g();
}
})();
}
expect: {
(function() {
(function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
(function() {
(b ? function() {} : function() {
f.a++;
f(1);
})();
})();
})();
})();
}
expect_stdout: [
"0",
"1",
]
}

View File

@@ -651,7 +651,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with explicit --no-rename", function(done) { it("Should work with explicit --no-rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -mc --no-rename"; var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n"); assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
@@ -659,7 +659,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with implicit --rename", function(done) { it("Should work with implicit --rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -mc"; var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(n){return n}\n"); assert.strictEqual(stdout, "function f(n){return n}\n");
@@ -667,7 +667,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with implicit --no-rename", function(done) { it("Should work with implicit --no-rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -c"; var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n"); assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");