Compare commits

...

21 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
Alex Lam S.L
346fa12e0e v3.1.9 2017-11-11 15:31:13 +08:00
Alex Lam S.L
cda27b0970 extend reduce_funcs to cover cross-scope substitutions (#2469)
fixes #2468
2017-11-11 15:30:17 +08:00
Alex Lam S.L
3c74047368 implement compress option reduce_funcs (#2466)
- inline single-use function declarations as expressions when permissible
- depend on `reduce_vars`
- enabled by default
- disable for speed critical code

fixes #2464
2017-11-11 05:59:35 +08:00
Alex Lam S.L
94525d859f fix object literal tracing in reduce_vars (#2461) 2017-11-10 05:47:10 +08:00
Alex Lam S.L
1127a2caf3 fix multiple nested function substitutions (#2458)
fixes #2449
2017-11-09 23:30:00 +08:00
Alex Lam S.L
246d9d4e83 remove hack in collapse_vars (#2457)
fixes #2456
2017-11-09 20:00:58 +08:00
Alex Lam S.L
4c0b0177b6 preserve function identity in reduce_vars (#2451)
fixes #2450
2017-11-08 03:28:46 +08:00
Alex Lam S.L
38bfb73f06 v3.1.8 2017-11-07 03:55:16 +08:00
Alex Lam S.L
bbedbf4ea0 handle circular function reference gracefully (#2446)
fixes #2442
2017-11-07 02:37:23 +08:00
Alex Lam S.L
2cfb5aa7da account for eval & with in reduce_vars (#2441)
fixes #2440
2017-11-06 16:10:57 +08:00
Alex Lam S.L
6c45101870 consolidate & enhance unused (#2439)
- defer declaration removal in `collapse_vars`
- account for `AST_SymbolFunarg` in deduplication
- private accounting for `collapse_vars`
- avoid issues with identity reference due to deep cloning

fixes #2437
2017-11-06 14:25:10 +08:00
Alex Lam S.L
2c2fd89e34 inline single-use functions that are not constant expressions (#2434)
fixes #2428
2017-11-05 22:14:11 +08:00
30 changed files with 2256 additions and 355 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,6 +689,12 @@ 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 to be
inlined as function expressions when permissible allowing further
optimization. Enabled by default. Option depends on `reduce_vars`
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.
@@ -859,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

@@ -75,6 +75,7 @@ function Compressor(options, false_by_default) {
properties : !false_by_default, properties : !false_by_default,
pure_getters : !false_by_default && "strict", pure_getters : !false_by_default && "strict",
pure_funcs : null, pure_funcs : null,
reduce_funcs : !false_by_default,
reduce_vars : !false_by_default, reduce_vars : !false_by_default,
sequences : !false_by_default, sequences : !false_by_default,
side_effects : !false_by_default, side_effects : !false_by_default,
@@ -150,7 +151,9 @@ merge(Compressor.prototype, {
} }
var passes = +this.options.passes || 1; var passes = +this.options.passes || 1;
var last_count = 1 / 0; var last_count = 1 / 0;
var mangle = { ie8: this.option("ie8") };
for (var pass = 0; pass < passes; pass++) { for (var pass = 0; pass < passes; pass++) {
node.figure_out_scope(mangle);
if (pass > 0 || this.option("reduce_vars")) if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this); node.reset_opt_flags(this);
node = node.transform(this); node = node.transform(this);
@@ -311,20 +314,14 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var d = node.definition(); var d = node.definition();
d.references.push(node); d.references.push(node);
var value;
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") { if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
d.fixed = false; d.fixed = false;
} else if (d.fixed) { } else if (d.fixed) {
var value = node.fixed_value(); value = node.fixed_value();
if (unused && value && d.references.length == 1) { if (value && ref_once(d)) {
if (value instanceof AST_Lambda) { d.single_use = value instanceof AST_Lambda
d.single_use = d.scope === node.scope || d.scope === node.scope && value.is_constant_expression();
&& !(d.orig[0] instanceof AST_SymbolFunarg)
|| value.is_constant_expression(node.scope);
} else {
d.single_use = d.scope === node.scope
&& loop_ids[d.id] === in_loop
&& value.is_constant_expression();
}
} else { } else {
d.single_use = false; d.single_use = false;
} }
@@ -334,11 +331,10 @@ merge(Compressor.prototype, {
} else { } else {
d.fixed = false; d.fixed = false;
} }
} else { }
}
mark_escaped(d, node, value, 0); mark_escaped(d, node, value, 0);
} }
}
}
if (node instanceof AST_SymbolCatch) { if (node instanceof AST_SymbolCatch) {
node.definition().fixed = false; node.definition().fixed = false;
} }
@@ -377,16 +373,15 @@ 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;
} else { } else {
d.fixed = node; d.fixed = node;
loop_ids[d.id] = in_loop;
mark(d, true); mark(d, true);
if (unused && d.references.length == 1) { d.single_use = ref_once(d);
d.single_use = d.scope === d.references[0].scope
|| node.is_constant_expression(d.references[0].scope);
}
} }
var save_ids = safe_ids; var save_ids = safe_ids;
safe_ids = Object.create(null); safe_ids = Object.create(null);
@@ -395,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
@@ -562,7 +558,7 @@ merge(Compressor.prototype, {
function reset_def(def) { function reset_def(def) {
def.direct_access = false; def.direct_access = false;
def.escaped = false; def.escaped = false;
if (def.scope.uses_eval) { if (def.scope.uses_eval || def.scope.uses_with) {
def.fixed = false; def.fixed = false;
} else if (!compressor.exposed(def)) { } else if (!compressor.exposed(def)) {
def.fixed = undefined; def.fixed = undefined;
@@ -574,6 +570,14 @@ merge(Compressor.prototype, {
def.single_use = undefined; def.single_use = undefined;
} }
function ref_once(def) {
return unused
&& !def.scope.uses_eval
&& !def.scope.uses_with
&& def.references.length == 1
&& loop_ids[def.id] === in_loop;
}
function is_immutable(value) { function is_immutable(value) {
if (!value) return false; if (!value) return false;
return value.is_constant() return value.is_constant()
@@ -608,8 +612,11 @@ merge(Compressor.prototype, {
&& parent.expression === node && parent.expression === node
&& (!(value instanceof AST_Function) || value.contains_this(parent))) { && (!(value instanceof AST_Function) || value.contains_this(parent))) {
return true; return true;
} else if (parent instanceof AST_Array || parent instanceof AST_Object) { } else if (parent instanceof AST_Array) {
return is_modified(parent, parent, level + 1); return is_modified(parent, parent, level + 1);
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
var obj = tw.parent(level + 1);
return is_modified(obj, obj, level + 2);
} else if (parent instanceof AST_PropAccess && parent.expression === node) { } else if (parent instanceof AST_PropAccess && parent.expression === node) {
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1); return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
} }
@@ -617,15 +624,19 @@ merge(Compressor.prototype, {
function mark_escaped(d, node, value, level) { function mark_escaped(d, node, value, level) {
var parent = tw.parent(level); var parent = tw.parent(level);
if (value instanceof AST_Constant || value instanceof AST_Function) return; if (value instanceof AST_Constant) return;
if (level > 0 && value instanceof AST_Function) return;
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression || parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope || parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) { || parent instanceof AST_VarDef && node === parent.value) {
d.escaped = true; d.escaped = true;
return; return;
} else if (parent instanceof AST_Array || parent instanceof AST_Object) { } else if (parent instanceof AST_Array) {
mark_escaped(d, parent, parent, level + 1); mark_escaped(d, parent, parent, level + 1);
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
var obj = tw.parent(level + 1);
mark_escaped(d, obj, obj, level + 2);
} else if (parent instanceof AST_PropAccess && node === parent.expression) { } else if (parent instanceof AST_PropAccess && node === parent.expression) {
value = read_property(value, parent.property); value = read_property(value, parent.property);
mark_escaped(d, parent, value, level + 1); mark_escaped(d, parent, value, level + 1);
@@ -786,6 +797,14 @@ merge(Compressor.prototype, {
|| compressor.option("unsafe") && global_names(this.name); || compressor.option("unsafe") && global_names(this.name);
}); });
function drop_decl(def) {
def.eliminated++;
if (def.orig.length == def.eliminated) {
def.scope.functions.del(def.name);
def.scope.variables.del(def.name);
}
}
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var CHANGED, max_iter = 10; var CHANGED, max_iter = 10;
do { do {
@@ -822,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) {
@@ -852,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
@@ -867,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,
@@ -880,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, {
@@ -905,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);
} }
@@ -939,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);
@@ -995,11 +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 > 1 && !(expr.name instanceof AST_SymbolFunarg) var declared = def.orig.length - def.eliminated;
|| def.references.length == 1 && !compressor.exposed(def)) { var referenced = def.references.length - def.replaced;
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 {
@@ -1007,6 +1084,10 @@ merge(Compressor.prototype, {
} }
} }
function get_rvalue(expr) {
return expr[expr instanceof AST_Assign ? "right" : "value"];
}
function get_lvalues(expr) { function get_lvalues(expr) {
var lvalues = Object.create(null); var lvalues = Object.create(null);
if (expr instanceof AST_Unary) return lvalues; if (expr instanceof AST_Unary) return lvalues;
@@ -1017,7 +1098,7 @@ merge(Compressor.prototype, {
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent()); lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
} }
}); });
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw); get_rvalue(expr).walk(tw);
return lvalues; return lvalues;
} }
@@ -1038,10 +1119,12 @@ merge(Compressor.prototype, {
var found = false; var found = false;
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) { return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
if (found) return node; if (found) return node;
if (node === expr) { if (node === expr || node.body === expr) {
found = true; found = true;
if (node instanceof AST_VarDef) { if (node instanceof AST_VarDef) {
remove(node.name.definition().orig, node.name); drop_decl(node.name.definition());
node.value = null;
return node;
} }
return in_list ? MAP.skip : null; return in_list ? MAP.skip : null;
} }
@@ -1050,16 +1133,12 @@ merge(Compressor.prototype, {
case 0: return null; case 0: return null;
case 1: return node.expressions[0]; case 1: return node.expressions[0];
} }
if (node instanceof AST_Definitions && node.definitions.length == 0
|| node instanceof AST_SimpleStatement && !node.body) {
return null;
}
})); }));
} }
function value_has_side_effects(expr) { function value_has_side_effects(expr) {
if (expr instanceof AST_Unary) return false; if (expr instanceof AST_Unary) return false;
return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor); return get_rvalue(expr).has_side_effects(compressor);
} }
function references_in_scope(def) { function references_in_scope(def) {
@@ -2187,7 +2266,10 @@ merge(Compressor.prototype, {
&& !self.variables.has(def.name)) { && !self.variables.has(def.name)) {
if (scope) { if (scope) {
var scope_def = scope.find_variable(node); var scope_def = scope.find_variable(node);
if (def.undeclared ? !scope_def : scope_def === def) return true; if (def.undeclared ? !scope_def : scope_def === def) {
result = "f";
return true;
}
} }
result = false; result = false;
} }
@@ -2301,7 +2383,7 @@ merge(Compressor.prototype, {
// this scope (not in nested scopes). // this scope (not in nested scopes).
var scope = this; var scope = this;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (node !== self) { if (node === self) return;
if (node instanceof AST_Defun) { if (node instanceof AST_Defun) {
if (!drop_funcs && scope === self) { if (!drop_funcs && scope === self) {
var node_def = node.name.definition(); var node_def = node.name.definition();
@@ -2313,6 +2395,9 @@ merge(Compressor.prototype, {
initializations.add(node.name.name, node); initializations.add(node.name.name, node);
return true; // don't go in nested scopes return true; // don't go in nested scopes
} }
if (node instanceof AST_SymbolFunarg && scope === self) {
var_defs_by_id.add(node.definition().id, node);
}
if (node instanceof AST_Definitions && scope === self) { if (node instanceof AST_Definitions && scope === self) {
node.definitions.forEach(function(def){ node.definitions.forEach(function(def){
var node_def = def.name.definition(); var node_def = def.name.definition();
@@ -2356,7 +2441,6 @@ merge(Compressor.prototype, {
scope = save_scope; scope = save_scope;
return true; return true;
} }
}
}); });
self.walk(tw); self.walk(tw);
// pass 2: for every used symbol we need to walk its // pass 2: for every used symbol we need to walk its
@@ -2413,7 +2497,7 @@ merge(Compressor.prototype, {
var def = node.name.definition(); var def = node.name.definition();
if (!(def.id in in_use_ids)) { if (!(def.id in in_use_ids)) {
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name)); compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
drop_decl(def, node.name); drop_decl(def);
return make_node(AST_EmptyStatement, node); return make_node(AST_EmptyStatement, node);
} }
return node; return node;
@@ -2435,7 +2519,7 @@ merge(Compressor.prototype, {
if (var_defs.length > 1 && !def.value) { if (var_defs.length > 1 && !def.value) {
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));
remove(var_defs, def); remove(var_defs, def);
drop_decl(sym, def.name); drop_decl(sym);
return; return;
} }
} }
@@ -2468,7 +2552,7 @@ merge(Compressor.prototype, {
} else { } else {
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name)); compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
} }
drop_decl(sym, def.name); drop_decl(sym);
} }
}); });
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) { if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
@@ -2477,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(), def.name);
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) {
@@ -2559,14 +2645,6 @@ merge(Compressor.prototype, {
col : sym.start.col col : sym.start.col
}; };
} }
function drop_decl(def, decl) {
remove(def.orig, decl);
if (!def.orig.length) {
def.scope.functions.del(def.name);
def.scope.variables.del(def.name);
}
}
} }
); );
self.transform(tt); self.transform(tt);
@@ -2702,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;
@@ -2720,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();
@@ -2751,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;
} }
})); }));
@@ -3286,7 +3373,7 @@ merge(Compressor.prototype, {
})); }));
if (reduce_vars) name.definition().fixed = false; if (reduce_vars) name.definition().fixed = false;
} }
remove(def.name.definition().orig, def.name); drop_decl(def.name.definition());
return a; return a;
}, []); }, []);
if (assignments.length == 0) return null; if (assignments.length == 0) return null;
@@ -3330,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, {
@@ -3374,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);
@@ -3445,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) {
@@ -3455,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)
@@ -3528,6 +3618,7 @@ merge(Compressor.prototype, {
&& !exp.uses_arguments && !exp.uses_arguments
&& !exp.uses_eval && !exp.uses_eval
&& exp.body.length == 1 && exp.body.length == 1
&& !exp.contains_this()
&& all(exp.argnames, function(arg) { && all(exp.argnames, function(arg) {
return arg.__unused; return arg.__unused;
}) })
@@ -3541,23 +3632,6 @@ merge(Compressor.prototype, {
expression: stat.body expression: stat.body
}); });
} }
if (value) {
var tw = new TreeWalker(function(node) {
if (!value) return true;
if (node instanceof AST_SymbolRef) {
var ref = node.scope.find_variable(node);
if (ref && ref.scope.parent_scope === fn.parent_scope) {
value = null;
return true;
}
}
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
value = null;
return true;
}
});
value.walk(tw);
}
if (value) { if (value) {
var args = self.args.concat(value); var args = self.args.concat(value);
return make_sequence(self, args).optimize(compressor); return make_sequence(self, args).optimize(compressor);
@@ -4220,6 +4294,17 @@ merge(Compressor.prototype, {
return self; return self;
}); });
function recursive_ref(compressor, def) {
var node;
for (var i = 0; node = compressor.parent(i); i++) {
if (node instanceof AST_Lambda) {
var name = node.name;
if (name && name.definition() === def) break;
}
}
return node;
}
OPT(AST_SymbolRef, function(self, compressor){ OPT(AST_SymbolRef, function(self, compressor){
var def = self.resolve_defines(compressor); var def = self.resolve_defines(compressor);
if (def) { if (def) {
@@ -4245,10 +4330,27 @@ merge(Compressor.prototype, {
if (fixed instanceof AST_Defun) { if (fixed instanceof AST_Defun) {
d.fixed = fixed = make_node(AST_Function, fixed, fixed); d.fixed = fixed = make_node(AST_Function, fixed, fixed);
} }
if (compressor.option("unused") if (d.single_use && fixed instanceof AST_Function) {
&& fixed if (d.scope !== self.scope
&& d.references.length == 1 && (!compressor.option("reduce_funcs")
&& d.single_use) { || d.escaped
|| fixed.inlined)) {
d.single_use = false;
} else if (recursive_ref(compressor, d)) {
d.single_use = false;
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
d.single_use = fixed.is_constant_expression(self.scope);
if (d.single_use == "f") {
var scope = self.scope;
do {
if (scope instanceof AST_Defun || scope instanceof AST_Function) {
scope.inlined = true;
}
} while (scope = scope.parent_scope);
}
}
}
if (d.single_use && fixed) {
var value = fixed.optimize(compressor); var value = fixed.optimize(compressor);
return value === fixed ? fixed.clone(true) : value; return value === fixed ? fixed.clone(true) : value;
} }

View File

@@ -137,11 +137,9 @@ function minify(files, options) {
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }
if (timings) timings.scope1 = Date.now();
if (options.compress) toplevel.figure_out_scope(options.mangle);
if (timings) timings.compress = Date.now(); if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel); if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope2 = Date.now(); if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle); if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now(); if (timings) timings.mangle = Date.now();
if (options.mangle) { if (options.mangle) {
@@ -199,9 +197,9 @@ function minify(files, options) {
if (timings) { if (timings) {
timings.end = Date.now(); timings.end = Date.now();
result.timings = { result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse), parse: 1e-3 * (timings.compress - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2), compress: 1e-3 * (timings.scope - timings.compress),
compress: 1e-3 * (timings.scope2 - timings.compress), scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle), mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties), properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output), output: 1e-3 * (timings.end - timings.output),

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

View File

@@ -129,6 +129,7 @@ constant_join_3: {
for_loop: { for_loop: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
unused: true, unused: true,
@@ -185,6 +186,7 @@ for_loop: {
index: { index: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -203,6 +205,7 @@ index: {
length: { length: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -221,6 +224,7 @@ length: {
index_length: { index_length: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,

View File

@@ -2,7 +2,8 @@ collapse_vars_side_effects_1: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -150,7 +151,8 @@ collapse_vars_issue_721: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
define(["require", "exports", 'handlebars'], function (require, exports, hb) { define(["require", "exports", 'handlebars'], function (require, exports, hb) {
@@ -216,7 +218,8 @@ collapse_vars_properties: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(obj) { function f1(obj) {
@@ -243,7 +246,8 @@ collapse_vars_if: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -293,7 +297,8 @@ collapse_vars_while: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(y) { function f1(y) {
@@ -712,7 +717,8 @@ collapse_vars_misc1: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f0(o, a, h) { function f0(o, a, h) {
@@ -789,7 +795,8 @@ collapse_vars_repeated: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -831,7 +838,8 @@ collapse_vars_closures: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function constant_vars_can_be_replaced_in_any_scope() { function constant_vars_can_be_replaced_in_any_scope() {
@@ -921,7 +929,8 @@ collapse_vars_try: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1() { function f1() {
@@ -1118,7 +1127,8 @@ collapse_vars_constants: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
reduce_funcs: true, reduce_vars:true
} }
input: { input: {
function f1(x) { function f1(x) {
@@ -1156,7 +1166,7 @@ collapse_vars_arguments: {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
toplevel:true, reduce_vars:true toplevel:true, reduce_funcs: true, reduce_vars:true
} }
input: { input: {
var outer = function() { var outer = function() {
@@ -1280,6 +1290,7 @@ collapse_vars_regexp: {
hoist_funs: true, hoist_funs: true,
keep_fargs: true, keep_fargs: true,
loops: false, loops: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -1355,6 +1366,7 @@ issue_1562: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1388,6 +1400,7 @@ issue_1605_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: false, toplevel: false,
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -1410,6 +1423,7 @@ issue_1605_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: "vars", toplevel: "vars",
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -1537,6 +1551,7 @@ issue_1631_3: {
var_side_effects_1: { var_side_effects_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1559,6 +1574,7 @@ var_side_effects_1: {
var_side_effects_2: { var_side_effects_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1584,6 +1600,7 @@ var_side_effects_3: {
collapse_vars: true, collapse_vars: true,
pure_getters: true, pure_getters: true,
unsafe: true, unsafe: true,
unused: true,
} }
input: { input: {
var print = console.log.bind(console); var print = console.log.bind(console);
@@ -1606,6 +1623,7 @@ var_side_effects_3: {
reduce_vars_assign: { reduce_vars_assign: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
@@ -1628,6 +1646,7 @@ reduce_vars_assign: {
iife_1: { iife_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1648,6 +1667,7 @@ iife_1: {
iife_2: { iife_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
toplevel: true, toplevel: true,
unused: false, unused: false,
@@ -1659,6 +1679,7 @@ iife_2: {
}(foo); }(foo);
} }
expect: { expect: {
var foo;
!function(x) { !function(x) {
console.log(x); console.log(x);
}(bar()); }(bar());
@@ -1945,6 +1966,7 @@ ref_scope: {
chained_1: { chained_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a = 2; var a = 2;
@@ -1961,6 +1983,7 @@ chained_1: {
chained_2: { chained_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a; var a;
@@ -2061,6 +2084,7 @@ inner_lvalues: {
double_def: { double_def: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a = x, a = a && y; var a = x, a = a && y;
@@ -2075,6 +2099,7 @@ double_def: {
toplevel_single_reference: { toplevel_single_reference: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
var a; var a;
@@ -2084,16 +2109,18 @@ toplevel_single_reference: {
} }
} }
expect: { expect: {
for (var b in x) {
var a; var a;
for (var b in x)
b(a = b); b(a = b);
} }
}
} }
unused_orig: { unused_orig: {
options = { options = {
collapse_vars: true, collapse_vars: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2132,6 +2159,7 @@ issue_315: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
keep_fargs: false, keep_fargs: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
unused: true, unused: true,
@@ -2358,6 +2386,7 @@ duplicate_argname: {
issue_2298: { issue_2298: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2723,6 +2752,7 @@ issue_2364_5: {
evaluate: true, evaluate: true,
pure_getters: true, pure_getters: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -2889,6 +2919,7 @@ pure_getters_chain: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: true, pure_getters: true,
unused: true,
} }
input: { input: {
function o(t, r) { function o(t, r) {
@@ -2909,6 +2940,7 @@ pure_getters_chain: {
conditional_1: { conditional_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
function f(a, b) { function f(a, b) {
@@ -2933,6 +2965,7 @@ conditional_1: {
conditional_2: { conditional_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true,
} }
input: { input: {
function f(a, b) { function f(a, b) {
@@ -3015,3 +3048,533 @@ issue_2425_3: {
} }
expect_stdout: "15" expect_stdout: "15"
} }
issue_2437: {
options = {
collapse_vars: true,
conditionals: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
function foo() {
bar();
}
function bar() {
if (xhrDesc) {
var req = new XMLHttpRequest();
var result = !!req.onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
return result;
}
else {
var req = new XMLHttpRequest();
var detectFunc = function () { };
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
return result;
}
}
foo();
}
expect: {
!function() {
if (xhrDesc)
return result = !!(req = new XMLHttpRequest()).onreadystatechange,
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
var req = new XMLHttpRequest(), detectFunc = function() {};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
}();
}
}
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

@@ -96,6 +96,7 @@ self_comparison_1: {
self_comparison_2: { self_comparison_2: {
options = { options = {
comparisons: true, comparisons: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }

View File

@@ -292,6 +292,7 @@ global_timeout_and_interval_symbols: {
issue_2233_2: { issue_2233_2: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unsafe: true, unsafe: true,
@@ -323,6 +324,7 @@ issue_2233_2: {
issue_2233_3: { issue_2233_3: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,

View File

@@ -673,6 +673,7 @@ issue_1539: {
vardef_value: { vardef_value: {
options = { options = {
keep_fnames: false, keep_fnames: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -734,6 +735,7 @@ assign_chain: {
issue_1583: { issue_1583: {
options = { options = {
keep_fargs: true, keep_fargs: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -1080,6 +1082,7 @@ var_catch_toplevel: {
options = { options = {
conditionals: true, conditionals: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -1113,7 +1116,8 @@ issue_2105_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
passes: 2, passes: 3,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -1153,9 +1157,10 @@ issue_2105_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
passes: 2, passes: 3,
properties: true, properties: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unsafe: true, unsafe: true,

View File

@@ -251,6 +251,7 @@ unsafe_constant: {
unsafe_object: { unsafe_object: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -279,6 +280,7 @@ unsafe_object: {
unsafe_object_nested: { unsafe_object_nested: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -307,6 +309,7 @@ unsafe_object_nested: {
unsafe_object_complex: { unsafe_object_complex: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -335,6 +338,7 @@ unsafe_object_complex: {
unsafe_object_repeated: { unsafe_object_repeated: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -363,6 +367,7 @@ unsafe_object_repeated: {
unsafe_object_accessor: { unsafe_object_accessor: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
} }
@@ -663,6 +668,7 @@ call_args: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -686,6 +692,7 @@ call_args_drop_param: {
evaluate: true, evaluate: true,
inline: true, inline: true,
keep_fargs: false, keep_fargs: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -1016,6 +1023,7 @@ Infinity_NaN_undefined_LHS: {
issue_1964_1: { issue_1964_1: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe_regexp: false, unsafe_regexp: false,
unused: true, unused: true,
@@ -1045,6 +1053,7 @@ issue_1964_1: {
issue_1964_2: { issue_1964_2: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe_regexp: true, unsafe_regexp: true,
unused: true, unused: true,
@@ -1201,6 +1210,7 @@ issue_2231_2: {
self_comparison_1: { self_comparison_1: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unsafe: true, unsafe: true,
@@ -1221,6 +1231,7 @@ self_comparison_2: {
evaluate: true, evaluate: true,
hoist_props: true, hoist_props: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,

View File

@@ -19,6 +19,7 @@ iifes_returning_constants_keep_fargs_true: {
booleans : true, booleans : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
reduce_funcs : true,
reduce_vars : true, reduce_vars : true,
cascade : true, cascade : true,
inline : true, inline : true,
@@ -55,6 +56,7 @@ iifes_returning_constants_keep_fargs_false: {
booleans : true, booleans : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
reduce_funcs : true,
reduce_vars : true, reduce_vars : true,
cascade : true, cascade : true,
inline : true, inline : true,
@@ -101,6 +103,7 @@ issue_1841_1: {
options = { options = {
keep_fargs: false, keep_fargs: false,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -127,6 +130,7 @@ issue_1841_2: {
options = { options = {
keep_fargs: false, keep_fargs: false,
pure_getters: false, pure_getters: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -154,6 +158,7 @@ function_returning_constant_literal: {
inline: true, inline: true,
passes: 2, passes: 2,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -305,6 +310,7 @@ issue_2084: {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -340,6 +346,7 @@ issue_2084: {
issue_2097: { issue_2097: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -508,3 +515,42 @@ issue_2114_2: {
} }
expect_stdout: "2" expect_stdout: "2"
} }
issue_2428: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function bar(k) {
console.log(k);
}
function foo(x) {
return bar(x);
}
function baz(a) {
foo(a);
}
baz(42);
baz("PASS");
}
expect: {
function baz(a) {
console.log(a);
}
baz(42);
baz("PASS");
}
expect_stdout: [
"42",
"PASS",
]
}

View File

@@ -3,6 +3,7 @@ issue_2377_1: {
evaluate: true, evaluate: true,
inline: true, inline: true,
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -35,6 +36,7 @@ issue_2377_2: {
inline: true, inline: true,
hoist_props: true, hoist_props: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -66,6 +68,7 @@ issue_2377_3: {
inline: true, inline: true,
hoist_props: true, hoist_props: true,
passes: 3, passes: 3,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -92,6 +95,7 @@ issue_2377_3: {
direct_access_1: { direct_access_1: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -120,6 +124,7 @@ direct_access_1: {
direct_access_2: { direct_access_2: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -143,6 +148,7 @@ direct_access_2: {
direct_access_3: { direct_access_3: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -163,6 +169,7 @@ direct_access_3: {
single_use: { single_use: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -187,6 +194,7 @@ single_use: {
name_collision_1: { name_collision_1: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -224,6 +232,7 @@ name_collision_1: {
name_collision_2: { name_collision_2: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -257,6 +266,7 @@ name_collision_2: {
name_collision_3: { name_collision_3: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
} }
@@ -293,6 +303,7 @@ contains_this_1: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -318,6 +329,7 @@ contains_this_2: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -345,6 +357,7 @@ contains_this_3: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -376,6 +389,7 @@ new_this: {
hoist_props: true, hoist_props: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -397,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

@@ -1,6 +1,7 @@
const_pragma: { const_pragma: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };
@@ -16,6 +17,7 @@ const_pragma: {
not_const: { not_const: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };

View File

@@ -2,6 +2,7 @@ chained_evaluation_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -28,6 +29,7 @@ chained_evaluation_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -15,6 +15,7 @@ f7: {
negate_iife: true, negate_iife: true,
passes: 3, passes: 3,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

View File

@@ -1,5 +1,6 @@
side_effects_catch: { side_effects_catch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -34,6 +35,7 @@ side_effects_catch: {
side_effects_else: { side_effects_else: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -62,6 +64,7 @@ side_effects_else: {
side_effects_finally: { side_effects_finally: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -98,6 +101,7 @@ side_effects_finally: {
side_effects_label: { side_effects_label: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -130,6 +134,7 @@ side_effects_label: {
side_effects_switch: { side_effects_switch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,

View File

@@ -2,6 +2,7 @@ unary_prefix: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -1,6 +1,7 @@
iife_for: { iife_for: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -26,6 +27,7 @@ iife_for: {
iife_for_in: { iife_for_in: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -51,6 +53,7 @@ iife_for_in: {
iife_do: { iife_do: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -80,6 +83,7 @@ iife_do: {
iife_while: { iife_while: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,

View File

@@ -3,6 +3,7 @@ collapse_vars_constants: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -240,6 +241,7 @@ negate_iife_issue_1073: {
evaluate: true, evaluate: true,
inline: true, inline: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
unused: true, unused: true,
@@ -267,6 +269,7 @@ issue_1288_side_effects: {
evaluate: true, evaluate: true,
inline: true, inline: true,
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -299,6 +302,7 @@ inner_var_for_in_1: {
options = { options = {
evaluate: true, evaluate: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
@@ -330,6 +334,7 @@ issue_1595_3: {
evaluate: true, evaluate: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }

View File

@@ -51,6 +51,7 @@ this_binding_collapse_vars: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: true, toplevel: true,
unused: true,
}; };
input: { input: {
var c = a; c(); var c = a; c();

View File

@@ -833,6 +833,7 @@ lhs_prop_2: {
evaluate: true, evaluate: true,
inline: true, inline: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -879,6 +880,7 @@ prop_side_effects_1: {
evaluate: true, evaluate: true,
inline: true, inline: true,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -915,6 +917,7 @@ prop_side_effects_2: {
inline: true, inline: true,
passes: 2, passes: 2,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,

View File

@@ -1,6 +1,7 @@
strict: { strict: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -30,6 +31,7 @@ strict: {
strict_reduce_vars: { strict_reduce_vars: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -58,6 +60,7 @@ strict_reduce_vars: {
unsafe: { unsafe: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -84,6 +87,7 @@ unsafe: {
unsafe_reduce_vars: { unsafe_reduce_vars: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -185,6 +189,7 @@ issue_2110_1: {
pure_getters: "strict", pure_getters: "strict",
sequences: true, sequences: true,
side_effects: true, side_effects: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -215,6 +220,7 @@ issue_2110_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -247,6 +253,7 @@ set_immutable_1: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -270,6 +277,7 @@ set_immutable_2: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -293,6 +301,7 @@ set_immutable_3: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -318,6 +327,7 @@ set_immutable_4: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -343,6 +353,7 @@ set_mutable_1: {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -367,6 +378,7 @@ set_mutable_2: {
cascade: true, cascade: true,
conditionals: true, conditionals: true,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

File diff suppressed because it is too large Load Diff

View File

@@ -187,6 +187,7 @@ dont_screw_try_catch_undefined: {
reduce_vars: { reduce_vars: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
ie8: true, ie8: true,
unused: true, unused: true,

View File

@@ -714,6 +714,7 @@ issue_1705_2: {
options = { options = {
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,

View File

@@ -297,4 +297,36 @@ describe("minify", function() {
assert.strictEqual(result.code, "alert({bar:42});"); assert.strictEqual(result.code, "alert({bar:42});");
}); });
}); });
describe("collapse_vars", function() {
it("Should not produce invalid AST", function() {
var code = [
"function f(a) {",
" a = x();",
" return a;",
"}",
"f();",
].join("\n");
var ast = Uglify.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
},
}).ast;
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 2);
assert.strictEqual(ast.body[0].TYPE, "Defun");
assert.strictEqual(ast.body[0].body.length, 2);
assert.strictEqual(ast.body[0].body[0].TYPE, "SimpleStatement");
var stat = ast.body[0].body[0];
Uglify.minify(ast, {
compress: {
sequences: false
}
});
assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()");
});
});
}); });