Compare commits

..

17 Commits

Author SHA1 Message Date
Alex Lam S.L
7c0c92943f v3.3.7 2018-01-14 09:13:26 +00:00
Alex Lam S.L
62a66dfff4 fix & extend join_vars for object assigments (#2781) 2018-01-14 17:11:31 +08:00
kzc
2cab348341 improve SymbolDef info in --output ast (#2778)
* SymbolDef info (a.k.a. `thedef`) is now represented as a string containing `"ID name [mangled_name]"`. 
* Enhance display of `globals`, `variables`, `functions` and `enclosed`.
* `SymbolDef.next_id` starts at `1` and the `id` is adjusted for `-o ast` display.
2018-01-14 01:40:51 +08:00
Alex Lam S.L
460218a3f8 v3.3.6 2018-01-13 05:37:42 +00:00
Alex Lam S.L
e49416e4aa fix reduce_vars on AST_Accessor (#2776)
fixes #2774
2018-01-13 02:46:14 +08:00
kzc
d4d7d99b70 add SymbolDef IDs to --output ast (#2772) 2018-01-12 15:41:09 +08:00
Alex Lam S.L
6a696d0a7b fix output of imported AST (#2771) 2018-01-12 01:05:49 +08:00
Alex Lam S.L
1c9e13f47d update dependencies (#2770)
- acorn@5.3.0
- commander@2.13.0
2018-01-12 00:32:17 +08:00
Alex Lam S.L
b757450cd8 fix nested unused assignments (#2769)
fixes #2768
2018-01-11 23:13:44 +08:00
Alex Lam S.L
23ec484806 fix corner case in #2763 (#2766) 2018-01-11 21:18:08 +08:00
Alex Lam S.L
f1e1bb419a join object assignments (#2763) 2018-01-11 17:08:21 +08:00
Alex Lam S.L
6a0af85c8b skip only vars in if_return (#2759)
fixes #2747
2018-01-10 19:08:46 +08:00
Alex Lam S.L
09269be974 enhance conditionals (#2758)
`x ? y || z : z` --> `x && y || z`
2018-01-10 16:59:57 +08:00
Alex Lam S.L
bf832cde16 improve synergy between compress and rename (#2755) 2018-01-09 17:55:41 +08:00
Alex Lam S.L
2972d58dbb patch variable declaractions extracted within catch (#2753)
fixes #2749
2018-01-09 13:54:35 +08:00
Alex Lam S.L
2e22d38a02 improve rename reproducibility (#2754)
fixes #2752
2018-01-09 13:53:05 +08:00
Alex Lam S.L
ce27bcd69a compress loops with immediate break (#2746)
fixes #2740
2018-01-08 14:30:18 +08:00
13 changed files with 758 additions and 166 deletions

View File

@@ -11,7 +11,7 @@ var path = require("path");
var program = require("commander"); var program = require("commander");
var UglifyJS = require("../tools/node"); var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ]; var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
var files = {}; var files = {};
var options = { var options = {
compress: false, compress: false,
@@ -223,7 +223,20 @@ function run() {
} }
fatal(ex); fatal(ex);
} else if (program.output == "ast") { } else if (program.output == "ast") {
if (!options.compress && !options.mangle) {
result.ast.figure_out_scope({});
}
print(JSON.stringify(result.ast, function(key, value) { print(JSON.stringify(result.ast, function(key, value) {
if (value) switch (key) {
case "thedef":
return symdef(value);
case "enclosed":
return value.length ? value.map(symdef) : undefined;
case "variables":
case "functions":
case "globals":
return value.size() ? value.map(symdef) : undefined;
}
if (skip_key(key)) return; if (skip_key(key)) return;
if (value instanceof UglifyJS.AST_Token) return; if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return; if (value instanceof UglifyJS.Dictionary) return;
@@ -377,6 +390,12 @@ function skip_key(key) {
return skip_keys.indexOf(key) >= 0; return skip_keys.indexOf(key) >= 0;
} }
function symdef(def) {
var ret = (1e6 + def.id) + " " + def.name;
if (def.mangled_name) ret += " " + def.mangled_name;
return ret;
}
function format_object(obj) { function format_object(obj) {
var lines = []; var lines = [];
var padding = ""; var padding = "";

View File

@@ -467,8 +467,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) d.references.push(node); if (node instanceof AST_SymbolRef) d.references.push(node);
d.fixed = false; d.fixed = false;
}); });
def(AST_Accessor, function(tw, descend) { def(AST_Accessor, function(tw, descend, compressor) {
push(tw); push(tw);
reset_variables(tw, compressor, this);
descend(); descend();
pop(tw); pop(tw);
return true; return true;
@@ -869,6 +870,7 @@ merge(Compressor.prototype, {
} }
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var scope = compressor.find_parent(AST_Scope);
var CHANGED, max_iter = 10; var CHANGED, max_iter = 10;
do { do {
CHANGED = false; CHANGED = false;
@@ -900,7 +902,6 @@ merge(Compressor.prototype, {
// Will not attempt to collapse assignments into or past code blocks // Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals. // which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) { function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope);
if (scope.uses_eval || scope.uses_with) return statements; if (scope.uses_eval || scope.uses_with) return statements;
var args; var args;
var candidates = []; var candidates = [];
@@ -1523,7 +1524,7 @@ merge(Compressor.prototype, {
function next_index(i) { function next_index(i) {
for (var j = i + 1, len = statements.length; j < len; j++) { for (var j = i + 1, len = statements.length; j < len; j++) {
var stat = statements[j]; var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) { if (!(stat instanceof AST_Var && declarations_only(stat))) {
break; break;
} }
} }
@@ -1533,7 +1534,7 @@ merge(Compressor.prototype, {
function prev_index(i) { function prev_index(i) {
for (var j = i; --j >= 0;) { for (var j = i; --j >= 0;) {
var stat = statements[j]; var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) { if (!(stat instanceof AST_Var && declarations_only(stat))) {
break; break;
} }
} }
@@ -1696,6 +1697,42 @@ merge(Compressor.prototype, {
statements.length = n; statements.length = n;
} }
function join_object_assignments(defn, body) {
if (!(defn instanceof AST_Definitions)) return;
var def = defn.definitions[defn.definitions.length - 1];
if (!(def.value instanceof AST_Object)) return;
var exprs;
if (body instanceof AST_Assign) {
exprs = [ body ];
} else if (body instanceof AST_Sequence) {
exprs = body.expressions.slice();
}
if (!exprs) return;
var trimmed = false;
do {
var node = exprs[0];
if (!(node instanceof AST_Assign)) break;
if (node.operator != "=") break;
if (!(node.left instanceof AST_PropAccess)) break;
var sym = node.left.expression;
if (!(sym instanceof AST_SymbolRef)) break;
if (def.name.name != sym.name) break;
if (!node.right.is_constant_expression(scope)) break;
var prop = node.left.property;
if (prop instanceof AST_Node) {
prop = prop.evaluate(compressor);
}
if (prop instanceof AST_Node) break;
def.value.properties.push(make_node(AST_ObjectKeyVal, node, {
key: prop,
value: node.right
}));
exprs.shift();
trimmed = true;
} while (exprs.length);
return trimmed && exprs;
}
function join_consecutive_vars(statements, compressor) { function join_consecutive_vars(statements, compressor) {
var defs; var defs;
for (var i = 0, j = -1, len = statements.length; i < len; i++) { for (var i = 0, j = -1, len = statements.length; i < len; i++) {
@@ -1712,8 +1749,26 @@ merge(Compressor.prototype, {
statements[++j] = stat; statements[++j] = stat;
defs = stat; defs = stat;
} }
} else if (stat instanceof AST_Exit) {
var exprs = join_object_assignments(prev, stat.value);
if (exprs) {
CHANGED = true;
if (exprs.length) {
stat.value = make_sequence(stat.value, exprs);
} else if (stat.value instanceof AST_Sequence) {
stat.value = stat.value.tail_node().left;
} else {
stat.value = stat.value.left;
}
}
statements[++j] = stat;
} else if (stat instanceof AST_For) { } else if (stat instanceof AST_For) {
if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) { var exprs = join_object_assignments(prev, stat.init);
if (exprs) {
CHANGED = true;
stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
statements[++j] = stat;
} else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
if (stat.init) { if (stat.init) {
prev.definitions = prev.definitions.concat(stat.init.definitions); prev.definitions = prev.definitions.concat(stat.init.definitions);
} }
@@ -1728,6 +1783,14 @@ merge(Compressor.prototype, {
} else { } else {
statements[++j] = stat; statements[++j] = stat;
} }
} else if (stat instanceof AST_SimpleStatement) {
var exprs = join_object_assignments(prev, stat.body);
if (exprs) {
CHANGED = true;
if (!exprs.length) continue;
stat.body = make_sequence(stat.body, exprs);
}
statements[++j] = stat;
} else { } else {
statements[++j] = stat; statements[++j] = stat;
} }
@@ -2774,7 +2837,7 @@ merge(Compressor.prototype, {
def.value.walk(tw); def.value.walk(tw);
} }
if (def.name.fixed_value() === def.value) { if (def.name.fixed_value() === def.value) {
fixed_ids[node_def.id] = true; fixed_ids[node_def.id] = def;
} }
} }
}); });
@@ -2803,9 +2866,7 @@ merge(Compressor.prototype, {
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;
if (node instanceof AST_Assign) { if (node instanceof AST_Assign) {
if (!in_use if (!in_use || def.id in fixed_ids && fixed_ids[def.id] !== node) {
|| def.id in fixed_ids
&& node.left.fixed_value() !== node.right) {
return maintain_this_binding(parent, node, node.right.transform(tt)); return maintain_this_binding(parent, node, node.right.transform(tt));
} }
} else if (!in_use) return make_node(AST_Number, node, { } else if (!in_use) return make_node(AST_Number, node, {
@@ -2859,25 +2920,29 @@ merge(Compressor.prototype, {
if (def.value) def.value = def.value.transform(tt); if (def.value) def.value = def.value.transform(tt);
var sym = def.name.definition(); var sym = def.name.definition();
if (!drop_vars || sym.id in in_use_ids) { if (!drop_vars || sym.id in in_use_ids) {
if (def.value && sym.id in fixed_ids && fixed_ids[sym.id] !== def) {
def.value = def.value.drop_side_effect_free(compressor);
}
if (def.name instanceof AST_SymbolVar) { if (def.name instanceof AST_SymbolVar) {
var var_defs = var_defs_by_id.get(sym.id); var var_defs = var_defs_by_id.get(sym.id);
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) { if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name)); compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
if (def.value) { if (def.value) {
side_effects.push(make_node(AST_Assign, def, { var assign = make_node(AST_Assign, def, {
operator: "=", operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name), left: make_node(AST_SymbolRef, def.name, def.name),
right: def.value right: def.value
}).transform(tt)); });
if (fixed_ids[sym.id] === def) {
fixed_ids[sym.id] = assign;
}
side_effects.push(assign.transform(tt));
} }
remove(var_defs, def); remove(var_defs, def);
sym.eliminated++; sym.eliminated++;
return; return;
} }
} }
if (def.value && sym.id in fixed_ids && def.name.fixed_value() !== def.value) {
def.value = def.value.drop_side_effect_free(compressor);
}
if (def.value) { if (def.value) {
if (side_effects.length > 0) { if (side_effects.length > 0) {
if (tail.length > 0) { if (tail.length > 0) {
@@ -2988,7 +3053,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_Assign) { if (node instanceof AST_Assign) {
node.right.walk(tw); node.right.walk(tw);
if (node.left.fixed_value() === node.right) { if (node.left.fixed_value() === node.right) {
fixed_ids[node_def.id] = true; fixed_ids[node_def.id] = node;
} }
} }
return true; return true;
@@ -3417,23 +3482,28 @@ merge(Compressor.prototype, {
}); });
function if_break_in_loop(self, compressor) { function if_break_in_loop(self, compressor) {
function drop_it(rest) {
rest = as_statement_array(rest);
if (self.body instanceof AST_BlockStatement) {
self.body = self.body.clone();
self.body.body = rest.concat(self.body.body.slice(1));
self.body = self.body.transform(compressor);
} else {
self.body = make_node(AST_BlockStatement, self.body, {
body: rest
}).transform(compressor);
}
if_break_in_loop(self, compressor);
}
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
if (compressor.option("dead_code") && is_break(first)) {
var body = [];
if (self.init instanceof AST_Statement) {
body.push(self.init);
} else if (self.init) {
body.push(make_node(AST_SimpleStatement, self.init, {
body: self.init
}));
}
if (self.condition) {
body.push(make_node(AST_SimpleStatement, self.condition, {
body: self.condition
}));
}
extract_declarations_from_unreachable_code(compressor, self.body, body);
return make_node(AST_BlockStatement, self, {
body: body
});
}
if (first instanceof AST_If) { if (first instanceof AST_If) {
if (first.body instanceof AST_Break if (is_break(first.body)) {
&& compressor.loopcontrol_target(first.body) === compressor.self()) {
if (self.condition) { if (self.condition) {
self.condition = make_node(AST_Binary, self.condition, { self.condition = make_node(AST_Binary, self.condition, {
left: self.condition, left: self.condition,
@@ -3444,9 +3514,7 @@ merge(Compressor.prototype, {
self.condition = first.condition.negate(compressor); self.condition = first.condition.negate(compressor);
} }
drop_it(first.alternative); drop_it(first.alternative);
} } else if (is_break(first.alternative)) {
else if (first.alternative instanceof AST_Break
&& compressor.loopcontrol_target(first.alternative) === compressor.self()) {
if (self.condition) { if (self.condition) {
self.condition = make_node(AST_Binary, self.condition, { self.condition = make_node(AST_Binary, self.condition, {
left: self.condition, left: self.condition,
@@ -3459,7 +3527,27 @@ merge(Compressor.prototype, {
drop_it(first.body); drop_it(first.body);
} }
} }
}; return self;
function is_break(node) {
return node instanceof AST_Break
&& compressor.loopcontrol_target(node) === compressor.self();
}
function drop_it(rest) {
rest = as_statement_array(rest);
if (self.body instanceof AST_BlockStatement) {
self.body = self.body.clone();
self.body.body = rest.concat(self.body.body.slice(1));
self.body = self.body.transform(compressor);
} else {
self.body = make_node(AST_BlockStatement, self.body, {
body: rest
}).transform(compressor);
}
self = if_break_in_loop(self, compressor);
}
}
OPT(AST_For, function(self, compressor){ OPT(AST_For, function(self, compressor){
if (!compressor.option("loops")) return self; if (!compressor.option("loops")) return self;
@@ -3495,8 +3583,7 @@ merge(Compressor.prototype, {
} }
} }
} }
if_break_in_loop(self, compressor); return if_break_in_loop(self, compressor);
return self;
}); });
OPT(AST_If, function(self, compressor){ OPT(AST_If, function(self, compressor){
@@ -3752,9 +3839,20 @@ merge(Compressor.prototype, {
OPT(AST_Try, function(self, compressor){ OPT(AST_Try, function(self, compressor){
tighten_body(self.body, compressor); 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 (all(self.body, is_empty)) { if (compressor.option("dead_code") && all(self.body, is_empty)) {
var body = []; var body = [];
if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body); if (self.bcatch) {
extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
body.forEach(function(stat) {
if (!(stat instanceof AST_Definitions)) return;
stat.definitions.forEach(function(var_def) {
var def = var_def.name.definition().redefined();
if (!def) return;
var_def.name = var_def.name.clone();
var_def.name.thedef = def;
});
});
}
if (self.bfinally) body = body.concat(self.bfinally.body); if (self.bfinally) body = body.concat(self.bfinally.body);
return make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: body body: body
@@ -5245,6 +5343,20 @@ merge(Compressor.prototype, {
consequent consequent
]).optimize(compressor); ]).optimize(compressor);
} }
// x ? y || z : z --> x && y || z
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: self.condition,
right: consequent.left
}),
right: alternative
}).optimize(compressor);
}
var in_bool = compressor.in_boolean_context(); var in_bool = compressor.in_boolean_context();
if (is_true(self.consequent)) { if (is_true(self.consequent)) {
if (is_false(self.alternative)) { if (is_false(self.alternative)) {

View File

@@ -454,7 +454,8 @@ function OutputStream(options) {
function prepend_comments(node) { function prepend_comments(node) {
var self = this; var self = this;
var start = node.start; var start = node.start;
if (!(start.comments_before && start.comments_before._dumped === self)) { if (!start) return;
if (start.comments_before && start.comments_before._dumped === self) return;
var comments = start.comments_before; var comments = start.comments_before;
if (!comments) { if (!comments) {
comments = start.comments_before = []; comments = start.comments_before = [];
@@ -527,18 +528,16 @@ function OutputStream(options) {
} }
} }
} }
}
function append_comments(node, tail) { function append_comments(node, tail) {
var self = this; var self = this;
var token = node.end; var token = node.end;
if (!token) return; if (!token) return;
var comments = token[tail ? "comments_before" : "comments_after"]; var comments = token[tail ? "comments_before" : "comments_after"];
if (comments if (!comments || comments._dumped === self) return;
&& comments._dumped !== self if (!(node instanceof AST_Statement || all(comments, function(c) {
&& (node instanceof AST_Statement || all(comments, function(c) {
return !/comment[134]/.test(c.type); return !/comment[134]/.test(c.type);
}))) { }))) return;
comments._dumped = self; comments._dumped = self;
var insert = OUTPUT.length; var insert = OUTPUT.length;
comments.filter(comment_filter, node).forEach(function(c, i) { comments.filter(comment_filter, node).forEach(function(c, i) {
@@ -563,7 +562,6 @@ function OutputStream(options) {
}); });
if (OUTPUT.length > insert) newline_insert = insert; if (OUTPUT.length > insert) newline_insert = insert;
} }
}
var stack = []; var stack = [];
return { return {

View File

@@ -464,59 +464,55 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
} }
}); });
AST_Toplevel.DEFMETHOD("find_unique_prefix", function(options) { AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
var cache = options.cache && options.cache.props; var cache = options.cache && options.cache.props;
var prefixes = Object.create(null); var avoid = Object.create(null);
options.reserved.forEach(add_prefix); options.reserved.forEach(to_avoid);
this.globals.each(add_def); this.globals.each(add_def);
this.walk(new TreeWalker(function(node) { this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def); if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition()); if (node instanceof AST_SymbolCatch) add_def(node.definition());
})); }));
var prefix, i = 0; return avoid;
do {
prefix = create_name(i++);
} while (prefixes[prefix]);
return prefix;
function add_prefix(name) { function to_avoid(name) {
if (/[0-9]$/.test(name)) { avoid[name] = true;
prefixes[name.replace(/[0-9]+$/, "")] = true;
}
} }
function add_def(def) { function add_def(def) {
var name = def.name; var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name); if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return; else if (!def.unmangleable(options)) return;
add_prefix(name); to_avoid(name);
}
function create_name(num) {
var name = "";
do {
name += letters[num % letters.length];
num = Math.floor(num / letters.length);
} while (num);
return name;
} }
}); });
AST_Toplevel.DEFMETHOD("expand_names", function(options) { AST_Toplevel.DEFMETHOD("expand_names", function(options) {
base54.reset();
base54.sort();
options = this._default_mangler_options(options); options = this._default_mangler_options(options);
var prefix = this.find_unique_prefix(options); var avoid = this.find_colliding_names(options);
var cname = 0;
this.globals.each(rename); this.globals.each(rename);
this.walk(new TreeWalker(function(node) { this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename); if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition()); if (node instanceof AST_SymbolCatch) rename(node.definition());
})); }));
function next_name() {
var name;
do {
name = base54(cname++);
} while (avoid[name] || !is_identifier(name));
return name;
}
function rename(def) { function rename(def) {
if (def.global || def.unmangleable(options)) return; if (def.global && options.cache) return;
if (def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return; if (member(def.name, options.reserved)) return;
var d = def.redefined(); var d = def.redefined();
def.name = d ? d.name : prefix + def.id; def.name = d ? d.name : next_name();
def.orig.forEach(function(sym) { def.orig.forEach(function(sym) {
sym.name = def.name; sym.name = def.name;
}); });

View File

@@ -4,20 +4,15 @@
"homepage": "http://lisperator.net/uglifyjs", "homepage": "http://lisperator.net/uglifyjs",
"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.3.5", "version": "3.3.7",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
"maintainers": [ "maintainers": [
"Alex Lam <alexlamsl@gmail.com>",
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)" "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
], ],
"repository": { "repository": "mishoo/UglifyJS2",
"type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git"
},
"bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues"
},
"main": "tools/node.js", "main": "tools/node.js",
"bin": { "bin": {
"uglifyjs": "bin/uglifyjs" "uglifyjs": "bin/uglifyjs"
@@ -29,11 +24,11 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.12.1", "commander": "~2.13.0",
"source-map": "~0.6.1" "source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.2.1", "acorn": "~5.3.0",
"mocha": "~3.5.1", "mocha": "~3.5.1",
"semver": "~5.4.1" "semver": "~5.4.1"
}, },

View File

@@ -2197,6 +2197,7 @@ toplevel_single_reference: {
unused_orig: { unused_orig: {
options = { options = {
collapse_vars: true, collapse_vars: true,
dead_code: true,
passes: 2, passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,

View File

@@ -1224,3 +1224,46 @@ hoist_decl: {
x() ? y() : z(); x() ? y() : z();
} }
} }
to_and_or: {
options = {
conditionals: true,
}
input: {
var values = [
0,
null,
true,
"foo",
false,
-1 / 0,
void 0,
];
values.forEach(function(x) {
values.forEach(function(y) {
values.forEach(function(z) {
console.log(x ? y || z : z);
});
});
});
}
expect: {
var values = [
0,
null,
true,
"foo",
false,
-1 / 0,
void 0,
];
values.forEach(function(x) {
values.forEach(function(y) {
values.forEach(function(z) {
console.log(x && y || z);
});
});
});
}
expect_stdout: true
}

View File

@@ -833,3 +833,32 @@ issue_2701: {
} }
expect_stdout: "function" expect_stdout: "function"
} }
issue_2749: {
options = {
dead_code: true,
inline: true,
toplevel: true,
unused: true,
}
input: {
var a = 2, c = "PASS";
while (a--)
(function() {
return b ? c = "FAIL" : b = 1;
try {
} catch (b) {
var b;
}
})();
console.log(c);
}
expect: {
var a = 2, c = "PASS";
while (a--)
b = void 0, b ? c = "FAIL" : b = 1;
var b;
console.log(c);
}
expect_stdout: "PASS"
}

View File

@@ -1644,3 +1644,51 @@ cascade_drop_assign: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
chained_3: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a, b) {
var c = a, c = b;
b++;
return c;
}(1, 2));
}
expect: {
console.log(function(a, b) {
var c = b;
b++;
return c;
}(0, 2));
}
expect_stdout: "2"
}
issue_2768: {
options = {
inline: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL", c = 1;
var c = function(b) {
var d = b = a;
var e = --b + (d && (a = "PASS"));
}();
console.log(a, typeof c);
}
expect: {
var a = "FAIL";
var c = (d = a, 0, void (d && (a = "PASS")));
var d;
console.log(a, typeof c);
}
expect_stdout: "PASS undefined"
}

View File

@@ -492,3 +492,116 @@ dead_code_condition: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_2740_1: {
options = {
dead_code: true,
loops: true,
}
input: {
for (; ; ) break;
for (a(); ; ) break;
for (; b(); ) break;
for (c(); d(); ) break;
for (; ; e()) break;
for (f(); ; g()) break;
for (; h(); i()) break;
for (j(); k(); l()) break;
}
expect: {
a();
b();
c();
d();
f();
h();
j();
k();
}
}
issue_2740_2: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: while (x()) {
break L1;
}
}
expect: {
x();
}
}
issue_2740_3: {
options = {
dead_code: true,
loops: true,
}
input: {
L1: for (var x = 0; x < 3; x++) {
L2: for (var y = 0; y < 2; y++) {
break L1;
}
}
console.log(x, y);
}
expect: {
L1: for (var x = 0; x < 3; x++)
for (var y = 0; y < 2; y++)
break L1;
console.log(x, y);
}
expect_stdout: "0 0"
}
issue_2740_4: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: for (var x = 0; x < 3; x++) {
L2: for (var y = 0; y < 2; y++) {
break L2;
}
}
console.log(x, y);
}
expect: {
for (var x = 0; x < 3; x++) {
var y = 0;
y < 2;
}
console.log(x, y);
}
expect_stdout: "3 0"
}
issue_2740_5: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: for (var x = 0; x < 3; x++) {
break L1;
L2: for (var y = 0; y < 2; y++) {
break L2;
}
}
console.log(x, y);
}
expect: {
var x = 0;
x < 3;
var y;
console.log(x,y);
}
expect_stdout: "0 undefined"
}

View File

@@ -1100,3 +1100,201 @@ const_prop_assign_pure: {
x(); x();
} }
} }
join_object_assignments_1: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function() {
var x = {
a: 1,
c: (console.log("c"), "C"),
};
x.b = 2;
x[3] = function() {
console.log(x);
},
x["a"] = /foo/,
x.bar = x;
return x;
}());
}
expect: {
console.log(function() {
var x = {
a: 1,
c: (console.log("c"), "C"),
b: 2,
3: function() {
console.log(x);
},
a: /foo/,
};
x.bar = x;
return x;
}());
}
expect_stdout: true
}
join_object_assignments_2: {
options = {
evaluate: true,
hoist_props: true,
join_vars: true,
passes: 3,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
foo: 1,
};
o.bar = 2;
o.baz = 3;
console.log(o.foo, o.bar + o.bar, o.foo * o.bar * o.baz);
}
expect: {
console.log(1, 4, 6);
}
expect_stdout: "1 4 6"
}
join_object_assignments_3: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function() {
var o = {
a: "PASS",
}, a = o.a;
o.a = "FAIL";
return a;
}());
}
expect: {
console.log(function() {
var o = {
a: "PASS",
}, a = o.a;
o.a = "FAIL";
return a;
}());
}
expect_stdout: "PASS"
}
join_object_assignments_4: {
options = {
join_vars: true,
}
input: {
console.log(function() {
var o = {
p: 3
};
return o.q = "foo";
}());
}
expect: {
console.log(function() {
var o = {
p: 3,
q: "foo"
};
return o.q;
}());
}
expect_stdout: "foo"
}
join_object_assignments_5: {
options = {
join_vars: true,
}
input: {
console.log(function() {
var o = {
p: 3
};
return o.q = /foo/,
o.r = "bar";
}());
}
expect: {
console.log(function() {
var o = {
p: 3,
q: /foo/,
r: "bar"
};
return o.r;
}());
}
expect_stdout: "bar"
}
join_object_assignments_6: {
options = {
join_vars: true,
}
input: {
console.log(function() {
var o = {
p: 3
};
return o.q = "foo",
o.p += "",
console.log(o.q),
o.p;
}());
}
expect: {
console.log(function() {
var o = {
p: 3,
q: "foo"
};
return o.p += "",
console.log(o.q),
o.p;
}());
}
expect_stdout: [
"foo",
"3",
]
}
join_object_assignments_7: {
options = {
join_vars: true,
}
input: {
console.log(function() {
var o = {
p: 3
};
for (o.q = "foo"; console.log(o.q););
return o.p;
}());
}
expect: {
console.log(function() {
for (var o = {
p: 3,
q: "foo"
}; console.log(o.q););
return o.p;
}());
}
expect_stdout: [
"foo",
"3",
]
}

View File

@@ -5276,3 +5276,29 @@ duplicate_lambda_defun_name_2: {
} }
expect_stdout: "0" expect_stdout: "0"
} }
issue_2774: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log({
get a() {
var b;
(b = true) && b.c;
b = void 0;
}
}.a);
}
expect: {
console.log({
get a() {
var b;
(b = true) && b.c;
b = void 0;
}
}.a);
}
expect_stdout: "undefined"
}

View File

@@ -373,4 +373,18 @@ describe("minify", function() {
assert.strictEqual(stat.print_to_string(), "a=x()"); assert.strictEqual(stat.print_to_string(), "a=x()");
}); });
}); });
describe("rename", function() {
it("Should be repeatable", function() {
var code = "!function(x){return x(x)}(y);";
for (var i = 0; i < 2; i++) {
assert.strictEqual(Uglify.minify(code, {
compress: {
toplevel: true,
},
rename: true,
}).code, "var a;(a=y)(a);");
}
});
});
}); });