Compare commits

...

9 Commits

Author SHA1 Message Date
Alex Lam S.L
667fc4d08b v3.1.10 2017-11-18 23:56:33 +08:00
kzc
6142117cdd document the webkit output option (#2490)
- workaround for WebKit bugs
- PhantomJS users should enable this output option

closes #2489
2017-11-17 13:46:49 +08:00
Alex Lam S.L
ae28a24c7f fix cross-scope inlining of AST_Functions (#2486)
fixes #2485
2017-11-16 10:04:30 +08:00
Alex Lam S.L
ebe761cad0 minor consolidations (#2484)
- unique symbol generation
- `unsafe` on `AST_Call`
2017-11-16 04:37:37 +08:00
kzc
fa7a7c5c5a Update ISSUE_TEMPLATE.md (#2481) 2017-11-15 06:00:51 +08:00
kzc
557636f3b7 update documentation for reduce_funcs (#2478) 2017-11-14 16:03:25 +08:00
Alex Lam S.L
49fbe9c5ac fix replacement logic in collapse_vars (#2475) 2017-11-13 07:37:42 +08:00
Alex Lam S.L
2ac5086831 fix top_retain on hoist_props (#2474)
fixes #2473
2017-11-13 00:59:41 +08:00
Alex Lam S.L
c6cfa04d10 allow symbol replacement on multiple occurrences (#2472)
- all-or-nothing replacement
- avoid unmangleable names

fixes #2436
2017-11-12 22:31:47 +08:00
10 changed files with 926 additions and 223 deletions

View File

@@ -15,6 +15,8 @@
UglifyJS alone - without third party tools or libraries. UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible. Ideally the input should be as small as possible.
Post a link to a gist if necessary. Post a link to a gist if necessary.
Issues without a reproducible test case will be closed.
--> -->
**The `uglifyjs` CLI command executed or `minify()` options used.** **The `uglifyjs` CLI command executed or `minify()` options used.**

View File

@@ -689,10 +689,11 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
Specify `"strict"` to treat `foo.bar` as side-effect-free only when Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`. `foo` is certain to not throw, i.e. not `null` or `undefined`.
- `reduce_funcs` (default: `true`) -- Allows single-use functions - `reduce_funcs` (default: `true`) -- Allows single-use functions to be
to be inlined as function expressions when permissible. inlined as function expressions when permissible allowing further
Enabled by default. Option depends on `reduce_vars` being enabled. optimization. Enabled by default. Option depends on `reduce_vars`
For speed critical code this option should be disabled. being enabled. Some code runs faster in the Chrome V8 engine if this
option is disabled. Does not negatively impact other major browsers.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and - `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values. used as constant values.
@@ -864,6 +865,9 @@ can pass additional arguments that control the code output:
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts) - `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
PhantomJS users should set this option to `true`.
- `width` (default `80`) -- only takes effect when beautification is on, this - `width` (default `80`) -- only takes effect when beautification is on, this
specifies an (orientative) line width that the beautifier will try to specifies an (orientative) line width that the beautifier will try to
obey. It refers to the width of the line text (excluding indentation). obey. It refers to the width of the line text (excluding indentation).

View File

@@ -15,7 +15,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", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ]; var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var files = {}; var files = {};
var options = { var options = {
compress: false, compress: false,

View File

@@ -352,11 +352,11 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null." $documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda); }, AST_Lambda);
var AST_Function = DEFNODE("Function", null, { var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression" $documentation: "A function expression"
}, AST_Lambda); }, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, { var AST_Defun = DEFNODE("Defun", "inlined", {
$documentation: "A function definition" $documentation: "A function definition"
}, AST_Lambda); }, AST_Lambda);

View File

@@ -373,6 +373,7 @@ merge(Compressor.prototype, {
} }
} }
if (node instanceof AST_Defun) { if (node instanceof AST_Defun) {
node.inlined = false;
var d = node.name.definition(); var d = node.name.definition();
if (compressor.exposed(d) || safe_to_read(d)) { if (compressor.exposed(d) || safe_to_read(d)) {
d.fixed = false; d.fixed = false;
@@ -389,6 +390,7 @@ merge(Compressor.prototype, {
return true; return true;
} }
if (node instanceof AST_Function) { if (node instanceof AST_Function) {
node.inlined = false;
push(); push();
var iife; var iife;
if (!node.name if (!node.name
@@ -796,8 +798,8 @@ merge(Compressor.prototype, {
}); });
function drop_decl(def) { function drop_decl(def) {
def._eliminiated = (def._eliminiated || 0) + 1; def.eliminated++;
if (def.orig.length == def._eliminiated) { if (def.orig.length == def.eliminated) {
def.scope.functions.del(def.name); def.scope.functions.del(def.name);
def.scope.variables.del(def.name); def.scope.variables.del(def.name);
} }
@@ -839,26 +841,7 @@ merge(Compressor.prototype, {
var args; var args;
var candidates = []; var candidates = [];
var stat_index = statements.length; var stat_index = statements.length;
while (--stat_index >= 0) { var scanner = new TreeTransformer(function(node, descend) {
// Treat parameters as collapsible in IIFE, i.e.
// function(a, b){ ... }(x());
// would be translated into equivalent assignments:
// var a = x(), b = undefined;
if (stat_index == 0 && compressor.option("unused")) extract_args();
// Find collapsible assignments
extract_candidates(statements[stat_index]);
while (candidates.length > 0) {
var candidate = candidates.pop();
var lhs = get_lhs(candidate);
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
// Locate symbols which may execute code outside of scanning range
var lvalues = get_lvalues(candidate);
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
var side_effects = value_has_side_effects(candidate);
var hit = candidate.name instanceof AST_SymbolFunarg;
var abort = false, replaced = false, can_replace = !args || !hit;
var tt = new TreeTransformer(function(node, descend) {
if (abort) return node; if (abort) return node;
// Skip nodes before `candidate` as quickly as possible // Skip nodes before `candidate` as quickly as possible
if (!hit) { if (!hit) {
@@ -869,7 +852,7 @@ merge(Compressor.prototype, {
return; return;
} }
// Stop immediately if these node types are encountered // Stop immediately if these node types are encountered
var parent = tt.parent(); var parent = scanner.parent();
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left) if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression) || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|| node instanceof AST_Debugger || node instanceof AST_Debugger
@@ -884,9 +867,13 @@ merge(Compressor.prototype, {
// Replace variable with assignment when found // Replace variable with assignment when found
if (can_replace if (can_replace
&& !(node instanceof AST_SymbolDeclaration) && !(node instanceof AST_SymbolDeclaration)
&& !is_lhs(node, parent)
&& lhs.equivalent_to(node)) { && lhs.equivalent_to(node)) {
CHANGED = replaced = abort = true; if (is_lhs(node, parent)) {
if (candidate.multiple) replaced++;
return node;
}
CHANGED = abort = true;
replaced++;
compressor.info("Collapsing {name} [{file}:{line},{col}]", { compressor.info("Collapsing {name} [{file}:{line},{col}]", {
name: node.print_to_string(), name: node.print_to_string(),
file: node.start.file, file: node.start.file,
@@ -897,8 +884,13 @@ merge(Compressor.prototype, {
return make_node(AST_UnaryPrefix, candidate, candidate); return make_node(AST_UnaryPrefix, candidate, candidate);
} }
if (candidate instanceof AST_VarDef) { if (candidate instanceof AST_VarDef) {
if (candidate.multiple) {
abort = false;
return node;
}
var def = candidate.name.definition(); var def = candidate.name.definition();
if (def.references.length == 1 && !compressor.exposed(def)) { if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
def.replaced++;
return maintain_this_binding(parent, node, candidate.value); return maintain_this_binding(parent, node, candidate.value);
} }
return make_node(AST_Assign, candidate, { return make_node(AST_Assign, candidate, {
@@ -922,26 +914,83 @@ merge(Compressor.prototype, {
|| side_effects && !references_in_scope(node.definition())) || side_effects && !references_in_scope(node.definition()))
|| (sym = lhs_or_def(node)) || (sym = lhs_or_def(node))
&& (sym instanceof AST_PropAccess || sym.name in lvalues) && (sym instanceof AST_PropAccess || sym.name in lvalues)
|| (side_effects || !one_off) || (side_effects || !replace_all)
&& (parent instanceof AST_Binary && lazy_op(parent.operator) && (parent instanceof AST_Binary && lazy_op(parent.operator)
|| parent instanceof AST_Case || parent instanceof AST_Case
|| parent instanceof AST_Conditional || parent instanceof AST_Conditional
|| parent instanceof AST_If)) { || parent instanceof AST_If)) {
if (!(node instanceof AST_Scope)) descend(node, tt); if (!(node instanceof AST_Scope)) descend(node, scanner);
abort = true; abort = true;
return node; return node;
} }
// Skip (non-executed) functions and (leading) default case in switch statements // Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node; if (node instanceof AST_Default || node instanceof AST_Scope) return node;
}); });
var multi_replacer = new TreeTransformer(function(node) {
if (abort) return node;
// Skip nodes before `candidate` as quickly as possible
if (!hit) {
if (node === candidate) {
hit = true;
return node;
}
return;
}
// Replace variable when found
if (node instanceof AST_SymbolRef
&& node.name == def.name) {
if (!--replaced) abort = true;
if (is_lhs(node, multi_replacer.parent())) return node;
def.replaced++;
value_def.replaced--;
return candidate.value;
}
// Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
});
while (--stat_index >= 0) {
// Treat parameters as collapsible in IIFE, i.e.
// function(a, b){ ... }(x());
// would be translated into equivalent assignments:
// var a = x(), b = undefined;
if (stat_index == 0 && compressor.option("unused")) extract_args();
// Find collapsible assignments
extract_candidates(statements[stat_index]);
while (candidates.length > 0) {
var candidate = candidates.pop();
var lhs = get_lhs(candidate);
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
// Locate symbols which may execute code outside of scanning range
var lvalues = get_lvalues(candidate);
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
var replace_all = candidate.multiple;
if (!replace_all && lhs instanceof AST_SymbolRef) {
var def = lhs.definition();
replace_all = def.references.length - def.replaced == 1;
}
var side_effects = value_has_side_effects(candidate);
var hit = candidate.name instanceof AST_SymbolFunarg;
var abort = false, replaced = 0, can_replace = !args || !hit;
if (!can_replace) { if (!can_replace) {
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; j < args.length; j++) { for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) {
args[j].transform(tt); args[j].transform(scanner);
} }
can_replace = true; can_replace = true;
} }
for (var i = stat_index; !abort && i < statements.length; i++) { for (var i = stat_index; !abort && i < statements.length; i++) {
statements[i].transform(tt); statements[i].transform(scanner);
}
if (candidate.multiple) {
var def = candidate.name.definition();
if (abort && def.references.length - def.replaced > replaced) replaced = false;
else {
abort = false;
hit = candidate.name instanceof AST_SymbolFunarg;
var value_def = candidate.value.definition();
for (var i = stat_index; !abort && i < statements.length; i++) {
statements[i].transform(multi_replacer);
}
}
} }
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1); if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
} }
@@ -956,7 +1005,7 @@ merge(Compressor.prototype, {
&& (iife = compressor.parent()) instanceof AST_Call && (iife = compressor.parent()) instanceof AST_Call
&& iife.expression === fn) { && iife.expression === fn) {
var fn_strict = compressor.has_directive("use strict"); var fn_strict = compressor.has_directive("use strict");
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false; if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
var len = fn.argnames.length; var len = fn.argnames.length;
args = iife.args.slice(len); args = iife.args.slice(len);
var names = Object.create(null); var names = Object.create(null);
@@ -1012,12 +1061,22 @@ merge(Compressor.prototype, {
} }
} }
function mangleable_var(expr) {
var value = expr.value;
if (!(value instanceof AST_SymbolRef)) return false;
if (value.name == "arguments") return false;
if (value.definition().undeclared) return false;
expr.multiple = true;
return true;
}
function get_lhs(expr) { function get_lhs(expr) {
if (expr instanceof AST_VarDef) { if (expr instanceof AST_VarDef) {
var def = expr.name.definition(); var def = expr.name.definition();
if (def.orig.length - (def._eliminiated || 0) > 1 var declared = def.orig.length - def.eliminated;
&& !(expr.name instanceof AST_SymbolFunarg) var referenced = def.references.length - def.replaced;
|| def.references.length == 1 && !compressor.exposed(def)) { if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)
|| (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) {
return make_node(AST_SymbolRef, expr.name, expr.name); return make_node(AST_SymbolRef, expr.name, expr.name);
} }
} else { } else {
@@ -2502,12 +2561,14 @@ merge(Compressor.prototype, {
var def = tail.pop(); var def = tail.pop();
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name)); compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
remove(var_defs, def); remove(var_defs, def);
drop_decl(def.name.definition());
side_effects.unshift(make_node(AST_Assign, def, { side_effects.unshift(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
})); }));
def = def.name.definition();
drop_decl(def);
def.replaced--;
} }
} }
if (head.length > 0 || tail.length > 0) { if (head.length > 0 || tail.length > 0) {
@@ -2719,17 +2780,29 @@ merge(Compressor.prototype, {
return self; return self;
}); });
AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
var var_names = this.var_names;
if (!var_names) {
this.var_names = var_names = Object.create(null);
this.enclosed.forEach(function(def) {
var_names[def.name] = true;
});
this.variables.each(function(def, name) {
var_names[name] = true;
});
}
prefix = prefix.replace(/[^a-z_$]+/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var_names[name] = true;
return name;
});
AST_Scope.DEFMETHOD("hoist_properties", function(compressor){ AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
var self = this; var self = this;
if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self; if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
var defs_by_id = Object.create(null); var defs_by_id = Object.create(null);
var var_names = Object.create(null);
self.enclosed.forEach(function(def) {
var_names[def.name] = true;
});
self.variables.each(function(def, name) {
var_names[name] = true;
});
return self.transform(new TreeTransformer(function(node) { return self.transform(new TreeTransformer(function(node) {
if (node instanceof AST_VarDef) { if (node instanceof AST_VarDef) {
var sym = node.name, def, value; var sym = node.name, def, value;
@@ -2737,6 +2810,7 @@ merge(Compressor.prototype, {
&& !(def = sym.definition()).escaped && !(def = sym.definition()).escaped
&& !def.single_use && !def.single_use
&& !def.direct_access && !def.direct_access
&& !top_retain(def)
&& (value = sym.fixed_value()) === node.value && (value = sym.fixed_value()) === node.value
&& value instanceof AST_Object) { && value instanceof AST_Object) {
var defs = new Dictionary(); var defs = new Dictionary();
@@ -2768,17 +2842,13 @@ merge(Compressor.prototype, {
} }
function make_sym(key) { function make_sym(key) {
var prefix = sym.name + "_" + key.toString().replace(/[^a-z_$]+/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var new_var = make_node(sym.CTOR, sym, { var new_var = make_node(sym.CTOR, sym, {
name: name, name: self.make_var_name(sym.name + "_" + key),
scope: self scope: self
}); });
var def = self.def_variable(new_var); var def = self.def_variable(new_var);
defs.set(key, def); defs.set(key, def);
self.enclosed.push(def); self.enclosed.push(def);
var_names[name] = true;
return new_var; return new_var;
} }
})); }));
@@ -3347,8 +3417,7 @@ merge(Compressor.prototype, {
self.args.length = last; self.args.length = last;
} }
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) { if (is_undeclared_ref(exp)) switch (exp.name) {
switch (exp.name) {
case "Array": case "Array":
if (self.args.length != 1) { if (self.args.length != 1) {
return make_node(AST_Array, self, { return make_node(AST_Array, self, {
@@ -3391,16 +3460,16 @@ merge(Compressor.prototype, {
operator: "!" operator: "!"
}).optimize(compressor); }).optimize(compressor);
break; break;
} } else if (exp instanceof AST_Dot) switch(exp.property) {
} case "toString":
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { if (self.args.length == 0) return make_node(AST_Binary, self, {
return make_node(AST_Binary, self, {
left: make_node(AST_String, self, { value: "" }), left: make_node(AST_String, self, { value: "" }),
operator: "+", operator: "+",
right: exp.expression right: exp.expression
}).optimize(compressor); }).optimize(compressor);
} break;
else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { case "join":
if (exp.expression instanceof AST_Array) EXIT: {
var separator; var separator;
if (self.args.length > 0) { if (self.args.length > 0) {
separator = self.args[0].evaluate(compressor); separator = self.args[0].evaluate(compressor);
@@ -3462,7 +3531,9 @@ merge(Compressor.prototype, {
node.expression.expression.elements = elements; node.expression.expression.elements = elements;
return best_of(compressor, self, node); return best_of(compressor, self, node);
} }
else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") { break;
case "charAt":
if (exp.expression.is_string(compressor)) {
var arg = self.args[0]; var arg = self.args[0];
var index = arg ? arg.evaluate(compressor) : 0; var index = arg ? arg.evaluate(compressor) : 0;
if (index !== arg) { if (index !== arg) {
@@ -3472,6 +3543,8 @@ merge(Compressor.prototype, {
}).optimize(compressor); }).optimize(compressor);
} }
} }
break;
}
} }
if (compressor.option("unsafe_Func") if (compressor.option("unsafe_Func")
&& is_undeclared_ref(exp) && is_undeclared_ref(exp)
@@ -4258,16 +4331,21 @@ merge(Compressor.prototype, {
d.fixed = fixed = make_node(AST_Function, fixed, fixed); d.fixed = fixed = make_node(AST_Function, fixed, fixed);
} }
if (d.single_use && fixed instanceof AST_Function) { if (d.single_use && fixed instanceof AST_Function) {
if (!compressor.option("reduce_funcs") && d.scope !== self.scope) { if (d.scope !== self.scope
&& (!compressor.option("reduce_funcs")
|| d.escaped
|| fixed.inlined)) {
d.single_use = false; d.single_use = false;
} else if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) { } else if (recursive_ref(compressor, d)) {
d.single_use = false; d.single_use = false;
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) { } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
d.single_use = fixed.is_constant_expression(self.scope); d.single_use = fixed.is_constant_expression(self.scope);
if (d.single_use == "f") { if (d.single_use == "f") {
var scope = self.scope; var scope = self.scope;
do { do {
if (scope.name) scope.name.definition().single_use = false; if (scope instanceof AST_Defun || scope instanceof AST_Function) {
scope.inlined = true;
}
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
} }
} }

View File

@@ -46,8 +46,10 @@
function SymbolDef(scope, index, orig) { function SymbolDef(scope, index, orig) {
this.name = orig.name; this.name = orig.name;
this.orig = [ orig ]; this.orig = [ orig ];
this.eliminated = 0;
this.scope = scope; this.scope = scope;
this.references = []; this.references = [];
this.replaced = 0;
this.global = false; this.global = false;
this.mangled_name = null; this.mangled_name = null;
this.undeclared = false; this.undeclared = false;

View File

@@ -4,7 +4,7 @@
"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.1.9", "version": "3.1.10",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -3098,3 +3098,483 @@ issue_2437: {
}(); }();
} }
} }
issue_2436_1: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log({
x: o.a,
y: o.b,
});
}
expect_stdout: true
}
issue_2436_2: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
o.a = 3;
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
o.a = 3;
return {
x: c.a,
y: c.b,
};
}(o));
}
expect_stdout: true
}
issue_2436_3: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
o = {
a: 3,
b: 4,
};
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
o = {
a: 3,
b: 4,
};
return {
x: c.a,
y: c.b,
};
}(o));
}
expect_stdout: true
}
issue_2436_4: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
var o;
}(o));
}
expect: {
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}({
a: 1,
b: 2,
}));
}
expect_stdout: true
}
issue_2436_5: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(o) {
return {
x: o.a,
y: o.b,
};
}(o));
}
expect: {
console.log(function(o) {
return {
x: o.a,
y: o.b,
};
}({
a: 1,
b: 2,
}));
}
expect_stdout: true
}
issue_2436_6: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
unsafe: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
console.log({
x: 1,
y: 2,
});
}
expect_stdout: true
}
issue_2436_7: {
options = {
collapse_vars: true,
hoist_props: true,
inline: true,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
console.log({
x: 1,
y: 2,
});
}
expect_stdout: true
}
issue_2436_8: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect_stdout: true
}
issue_2436_9: {
options = {
collapse_vars: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = console;
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect: {
var o = console;
console.log(function(c) {
return {
x: c.a,
y: c.b,
};
}(o));
}
expect_stdout: true
}
issue_2436_10: {
options = {
collapse_vars: true,
inline: true,
pure_getters: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
function f(n) {
o = { b: 3 };
return n;
}
console.log(function(c) {
return [
c.a,
f(c.b),
c.b,
];
}(o).join(" "));
}
expect: {
var o = {
a: 1,
b: 2,
};
function f(n) {
o = { b: 3 };
return n;
}
console.log(function(c) {
return [
c.a,
f(c.b),
c.b,
];
}(o).join(" "));
}
expect_stdout: "1 2 2"
}
issue_2436_11: {
options = {
collapse_vars: true,
join_vars: true,
reduce_vars: true,
unused: true,
}
input: {
function matrix() {}
function isCollection() {}
function _randomDataForMatrix() {}
function _randomInt() {}
function f(arg1, arg2) {
if (isCollection(arg1)) {
var size = arg1;
var max = arg2;
var min = 0;
var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
return size && true === size.isMatrix ? matrix(res) : res;
} else {
var min = arg1;
var max = arg2;
return _randomInt(min, max);
}
}
}
expect: {
function matrix() {}
function isCollection() {}
function _randomDataForMatrix() {}
function _randomInt() {}
function f(arg1, arg2) {
if (isCollection(arg1)) {
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
return size && true === size.isMatrix ? matrix(res) : res;
} else {
return _randomInt(min = arg1, max = arg2);
}
}
}
}
issue_2436_12: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function isUndefined() {}
function f() {
var viewValue = this.$$lastCommittedViewValue;
var modelValue = viewValue;
return isUndefined(modelValue) ? modelValue : null;
}
}
expect: {
function isUndefined() {}
function f() {
var modelValue = this.$$lastCommittedViewValue;
return isUndefined(modelValue) ? modelValue : null;
}
}
}
issue_2436_13: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
(function() {
function f(b) {
(function g(b) {
var b = b && (b.null = "FAIL");
})(a);
}
f();
})();
console.log(a);
}
expect: {
var a = "PASS";
(function() {
(function(b) {
(function(b) {
a && (a.null = "FAIL");
})();
})();
})();
console.log(a);
}
expect_stdout: "PASS"
}
issue_2436_14: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
var b = {};
(function() {
var c = a;
c && function(c, d) {
console.log(c, d);
}(b, c);
})();
}
expect: {
var a = "PASS";
var b = {};
(function() {
a && function(c, d) {
console.log(c, d);
}(b, a);
})();
}
expect_stdout: true
}

View File

@@ -411,3 +411,92 @@ new_this: {
} }
expect_stdout: "1 2" expect_stdout: "1 2"
} }
issue_2473_1: {
options = {
hoist_props: false,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_2: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_3: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect_stdout: "1 2"
}
issue_2473_4: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
(function() {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
})();
}
expect: {
(function() {
var o_a = 1, o_b = 2;
console.log(o_a, o_b);
})();
}
expect_stdout: "1 2"
}

View File

@@ -4477,3 +4477,51 @@ perf_8: {
} }
expect_stdout: "348150" expect_stdout: "348150"
} }
issue_2485: {
options = {
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
var foo = function(bar) {
var n = function(a, b) {
return a + b;
};
var sumAll = function(arg) {
return arg.reduce(n, 0);
};
var runSumAll = function(arg) {
return sumAll(arg);
};
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect: {
var foo = function(bar) {
var n = function(a, b) {
return a + b;
};
var runSumAll = function(arg) {
return function(arg) {
return arg.reduce(n, 0);
}(arg);
};
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect_stdout: "6"
}