Merge branch 'master' into harmony-v3.3.6

This commit is contained in:
alexlamsl
2018-01-13 13:53:31 +08:00
13 changed files with 636 additions and 164 deletions

View File

@@ -11,7 +11,7 @@ var path = require("path");
var program = require("commander");
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 options = {
compress: false,
@@ -234,7 +234,33 @@ function run() {
}
fatal(ex);
} else if (program.output == "ast") {
if (!options.compress && !options.mangle) {
result.ast.figure_out_scope({});
}
print(JSON.stringify(result.ast, function(key, value) {
switch (key) {
case "thedef":
if (typeof value == "object" && typeof value.id == "number") {
return value.id;
}
return;
case "enclosed":
return value.map(function(sym){
return sym.id;
});
case "variables":
case "functions":
case "globals":
if (value && value.size()) {
var ret = {};
value.each(function(val, key) {
// key/val inverted for readability.
ret[val.id] = key;
});
return ret;
}
return;
}
if (skip_key(key)) return;
if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return;

View File

@@ -489,8 +489,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) d.references.push(node);
d.fixed = false;
});
def(AST_Accessor, function(tw, descend) {
def(AST_Accessor, function(tw, descend, compressor) {
push(tw);
reset_variables(tw, compressor, this);
descend();
pop(tw);
return true;
@@ -947,6 +948,7 @@ merge(Compressor.prototype, {
}
function tighten_body(statements, compressor) {
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
var CHANGED, max_iter = 10;
do {
CHANGED = false;
@@ -978,7 +980,6 @@ merge(Compressor.prototype, {
// Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
if (scope.uses_eval || scope.uses_with) return statements;
var args;
var candidates = [];
@@ -1640,7 +1641,7 @@ merge(Compressor.prototype, {
function next_index(i) {
for (var j = i + 1, len = statements.length; j < len; j++) {
var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
if (!(stat instanceof AST_Var && declarations_only(stat))) {
break;
}
}
@@ -1650,7 +1651,7 @@ merge(Compressor.prototype, {
function prev_index(i) {
for (var j = i; --j >= 0;) {
var stat = statements[j];
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
if (!(stat instanceof AST_Var && declarations_only(stat))) {
break;
}
}
@@ -1813,6 +1814,41 @@ merge(Compressor.prototype, {
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.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) {
var defs;
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
@@ -1845,6 +1881,14 @@ merge(Compressor.prototype, {
} else {
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 {
statements[++j] = stat;
}
@@ -2952,7 +2996,7 @@ merge(Compressor.prototype, {
var node_def = def.name.definition();;
initializations.add(node_def.id, def.value);
if (def.name.fixed_value() === def.value) {
fixed_ids[node_def.id] = true;
fixed_ids[node_def.id] = def;
}
}
if (def.value.has_side_effects(compressor)) {
@@ -2988,9 +3032,7 @@ merge(Compressor.prototype, {
var def = sym.definition();
var in_use = def.id in in_use_ids;
if (node instanceof AST_Assign) {
if (!in_use
|| def.id in fixed_ids
&& node.left.fixed_value() !== node.right) {
if (!in_use || def.id in fixed_ids && fixed_ids[def.id] !== node) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
} else if (!in_use) return make_node(AST_Number, node, {
@@ -3059,25 +3101,29 @@ merge(Compressor.prototype, {
var sym = def.name.definition();
if (drop_block && sym.global) return tail.push(def);
if (!(drop_vars || drop_block) || 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) {
var var_defs = var_defs_by_id.get(sym.id);
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));
if (def.value) {
side_effects.push(make_node(AST_Assign, def, {
var assign = make_node(AST_Assign, def, {
operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name),
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);
sym.eliminated++;
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 (side_effects.length > 0) {
if (tail.length > 0) {
@@ -3196,7 +3242,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_Assign) {
node.right.walk(tw);
if (node.left.fixed_value() === node.right) {
fixed_ids[node_def.id] = true;
fixed_ids[node_def.id] = node;
}
}
return true;
@@ -3648,23 +3694,28 @@ merge(Compressor.prototype, {
});
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;
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.body instanceof AST_Break
&& compressor.loopcontrol_target(first.body) === compressor.self()) {
if (is_break(first.body)) {
if (self.condition) {
self.condition = make_node(AST_Binary, self.condition, {
left: self.condition,
@@ -3675,9 +3726,7 @@ merge(Compressor.prototype, {
self.condition = first.condition.negate(compressor);
}
drop_it(first.alternative);
}
else if (first.alternative instanceof AST_Break
&& compressor.loopcontrol_target(first.alternative) === compressor.self()) {
} else if (is_break(first.alternative)) {
if (self.condition) {
self.condition = make_node(AST_Binary, self.condition, {
left: self.condition,
@@ -3690,7 +3739,27 @@ merge(Compressor.prototype, {
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){
if (!compressor.option("loops")) return self;
@@ -3726,8 +3795,7 @@ merge(Compressor.prototype, {
}
}
}
if_break_in_loop(self, compressor);
return self;
return if_break_in_loop(self, compressor);
});
OPT(AST_If, function(self, compressor){
@@ -3983,9 +4051,20 @@ merge(Compressor.prototype, {
OPT(AST_Try, function(self, compressor){
tighten_body(self.body, compressor);
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 = [];
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);
return make_node(AST_BlockStatement, self, {
body: body
@@ -5576,6 +5655,20 @@ merge(Compressor.prototype, {
consequent
]).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();
if (is_true(self.consequent)) {
if (is_false(self.alternative)) {

View File

@@ -476,79 +476,78 @@ function OutputStream(options) {
var self = this;
var start = node.start;
if (!start) return;
if (!(start.comments_before && start.comments_before._dumped === self)) {
var comments = start.comments_before;
if (!comments) {
comments = start.comments_before = [];
}
comments._dumped = self;
if (start.comments_before && start.comments_before._dumped === self) return;
var comments = start.comments_before;
if (!comments) {
comments = start.comments_before = [];
}
comments._dumped = self;
if (node instanceof AST_Exit && node.value) {
var tw = new TreeWalker(function(node) {
var parent = tw.parent();
if (parent instanceof AST_Exit
|| parent instanceof AST_Binary && parent.left === node
|| parent.TYPE == "Call" && parent.expression === node
|| parent instanceof AST_Conditional && parent.condition === node
|| parent instanceof AST_Dot && parent.expression === node
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) {
if (!node.start) return;
var text = node.start.comments_before;
if (text && text._dumped !== self) {
text._dumped = self;
comments = comments.concat(text);
}
} else {
return true;
if (node instanceof AST_Exit && node.value) {
var tw = new TreeWalker(function(node) {
var parent = tw.parent();
if (parent instanceof AST_Exit
|| parent instanceof AST_Binary && parent.left === node
|| parent.TYPE == "Call" && parent.expression === node
|| parent instanceof AST_Conditional && parent.condition === node
|| parent instanceof AST_Dot && parent.expression === node
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) {
if (!node.start) return;
var text = node.start.comments_before;
if (text && text._dumped !== self) {
text._dumped = self;
comments = comments.concat(text);
}
});
tw.push(node);
node.value.walk(tw);
}
if (current_pos == 0) {
if (comments.length > 0 && options.shebang && comments[0].type == "comment5") {
print("#!" + comments.shift().value + "\n");
indent();
}
var preamble = options.preamble;
if (preamble) {
print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(comment_filter, node);
if (comments.length == 0) return;
var last_nlb = /(^|\n) *$/.test(OUTPUT);
comments.forEach(function(c, i) {
if (!last_nlb) {
if (c.nlb) {
print("\n");
indent();
last_nlb = true;
} else if (i > 0) {
space();
}
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
indent();
last_nlb = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
last_nlb = false;
} else {
return true;
}
});
tw.push(node);
node.value.walk(tw);
}
if (current_pos == 0) {
if (comments.length > 0 && options.shebang && comments[0].type == "comment5") {
print("#!" + comments.shift().value + "\n");
indent();
}
var preamble = options.preamble;
if (preamble) {
print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(comment_filter, node);
if (comments.length == 0) return;
var last_nlb = /(^|\n) *$/.test(OUTPUT);
comments.forEach(function(c, i) {
if (!last_nlb) {
if (start.nlb) {
if (c.nlb) {
print("\n");
indent();
} else {
last_nlb = true;
} else if (i > 0) {
space();
}
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
indent();
last_nlb = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
last_nlb = false;
}
});
if (!last_nlb) {
if (start.nlb) {
print("\n");
indent();
} else {
space();
}
}
}
@@ -557,35 +556,33 @@ function OutputStream(options) {
var token = node.end;
if (!token) return;
var comments = token[tail ? "comments_before" : "comments_after"];
if (comments
&& comments._dumped !== self
&& (node instanceof AST_Statement || all(comments, function(c) {
return !/comment[134]/.test(c.type);
}))) {
comments._dumped = self;
var insert = OUTPUT.length;
comments.filter(comment_filter, node).forEach(function(c, i) {
need_space = false;
if (need_newline_indented) {
print("\n");
indent();
need_newline_indented = false;
} else if (c.nlb && (i > 0 || !/(^|\n) *$/.test(OUTPUT))) {
print("\n");
indent();
} else if (i > 0 || !tail) {
space();
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
need_newline_indented = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
need_space = true;
}
});
if (OUTPUT.length > insert) newline_insert = insert;
}
if (!comments || comments._dumped === self) return;
if (!(node instanceof AST_Statement || all(comments, function(c) {
return !/comment[134]/.test(c.type);
}))) return;
comments._dumped = self;
var insert = OUTPUT.length;
comments.filter(comment_filter, node).forEach(function(c, i) {
need_space = false;
if (need_newline_indented) {
print("\n");
indent();
need_newline_indented = false;
} else if (c.nlb && (i > 0 || !/(^|\n) *$/.test(OUTPUT))) {
print("\n");
indent();
} else if (i > 0 || !tail) {
space();
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
need_newline_indented = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
need_space = true;
}
});
if (OUTPUT.length > insert) newline_insert = insert;
}
var stack = [];

View File

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

View File

@@ -4,17 +4,15 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.3.5",
"version": "3.3.6",
"engines": {
"node": ">=0.8.0"
},
"maintainers": [
"Alex Lam <alexlamsl@gmail.com>",
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
],
"repository": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
"bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues"
},
"repository": "https://github.com/mishoo/UglifyJS2.git#harmony",
"main": "tools/node.js",
"bin": {
"uglifyjs": "bin/uglifyjs"
@@ -26,11 +24,11 @@
"LICENSE"
],
"dependencies": {
"commander": "~2.12.1",
"commander": "~2.13.0",
"source-map": "~0.6.1"
},
"devDependencies": {
"acorn": "~5.2.1",
"acorn": "~5.3.0",
"mocha": "~3.5.1",
"semver": "~5.4.1"
},

View File

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

View File

@@ -1224,3 +1224,46 @@ hoist_decl: {
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

@@ -1128,3 +1128,32 @@ issue_2701: {
}
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

@@ -2018,3 +2018,51 @@ cascade_drop_assign: {
}
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

@@ -536,3 +536,116 @@ dead_code_condition: {
}
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

@@ -1377,3 +1377,91 @@ const_prop_assign_pure: {
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"
}

View File

@@ -5866,3 +5866,29 @@ issue_2757_2: {
]
node_version: ">=6"
}
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

@@ -404,4 +404,18 @@ describe("minify", function() {
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);");
}
});
});
});