Compare commits

...

32 Commits

Author SHA1 Message Date
Alex Lam S.L
9632f79e46 harmony-v3.1.9 2017-11-11 19:21:09 +08:00
alexlamsl
a3fbb27194 update tests 2017-11-11 15:57:47 +08:00
alexlamsl
11c0b1e1f9 Merge branch 'master' into harmony-v3.1.9 2017-11-11 15:45:34 +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
650d5d5c9b suppress hoist_props on export (#2463)
Miscellaneous
- fix double semi-colons from `beautify` in `export`

fixes #2462
2017-11-10 17:38:31 +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
dd0a36119b fix const under collapse_vars without unused (#2454)
fixes #2453
2017-11-08 02:10:46 +08:00
Alex Lam S.L
94b19a9c46 harmony-v3.1.8 2017-11-07 06:05:40 +08:00
alexlamsl
bcf95ac02c update tests 2017-11-07 04:49:57 +08:00
alexlamsl
e11cec1ab8 Merge branch 'master' into harmony 2017-11-07 04:30:40 +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
Alex Lam S.L
0c43519097 harmony-v3.1.7 2017-11-05 17:25:57 +08:00
alexlamsl
352a7de204 update tests 2017-11-05 16:48:00 +08:00
alexlamsl
df9c8dfd72 Merge branch 'master' into harmony-v3.1.7 2017-11-05 15:47:40 +08:00
Alex Lam S.L
f46281e2b7 v3.1.7 2017-11-05 15:03:19 +08:00
Alex Lam S.L
25a18883f5 tweak #2424 (#2432) 2017-11-05 12:49:14 +08:00
Alex Lam S.L
5b4b07e9a7 extend function inlining safety checks (#2430) 2017-11-05 06:18:45 +08:00
Alex Lam S.L
a8aa28a7a6 consolidate single-use function reduction (#2427)
fixes #2423
2017-11-05 04:27:01 +08:00
Alex Lam S.L
fe5a68f9d5 maintain call argument order in collapse_vars (#2426)
fixes #2425
2017-11-05 00:00:18 +08:00
Alex Lam S.L
71e61153b1 improve variations on call arguments for ufuzz (#2424) 2017-11-04 16:29:42 +08:00
Alex Lam S.L
c8b6f4733d reduce this within functions (#2421)
- only replace same-scope usages
- augment `test/ufuzz.js` to test for `this`


fixes #2420
2017-11-04 00:31:37 +08:00
kzc
29bbc41dfe hoist_props: implement limited hoisting of class expressions (#2415) 2017-10-30 23:20:54 +08:00
Alex Lam S.L
a48f87abf2 compress new function containing this (#2417) 2017-10-30 23:19:27 +08:00
35 changed files with 2138 additions and 241 deletions

View File

@@ -706,6 +706,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
`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.
Enabled by default. Option depends on `reduce_vars` being enabled.
For speed critical code this option should be disabled.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values.

View File

@@ -78,6 +78,7 @@ function Compressor(options, false_by_default) {
properties : !false_by_default,
pure_getters : !false_by_default && "strict",
pure_funcs : null,
reduce_funcs : !false_by_default,
reduce_vars : !false_by_default,
sequences : !false_by_default,
side_effects : !false_by_default,
@@ -156,7 +157,9 @@ merge(Compressor.prototype, {
}
var passes = +this.options.passes || 1;
var last_count = 1 / 0;
var mangle = { ie8: this.option("ie8") };
for (var pass = 0; pass < passes; pass++) {
node.figure_out_scope(mangle);
if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this);
node = node.transform(this);
@@ -291,7 +294,7 @@ merge(Compressor.prototype, {
self.transform(tt);
});
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) {
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
var reduce_vars = compressor.option("reduce_vars");
var unused = compressor.option("unused");
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
@@ -318,16 +321,16 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) {
var d = node.definition();
d.references.push(node);
var value;
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
d.fixed = false;
} else if (d.fixed) {
var value = node.fixed_value();
if (unused && !compressor.exposed(d)) {
d.single_use = value
&& d.references.length == 1
&& loop_ids[d.id] === in_loop
&& d.scope === node.scope
&& value.is_constant_expression();
value = node.fixed_value();
if (value && ref_once(d) && !compressor.exposed(d)) {
d.single_use = value instanceof AST_Lambda
|| d.scope === node.scope && value.is_constant_expression();
} else {
d.single_use = false;
}
if (is_modified(node, value, 0, is_immutable(value))) {
if (d.single_use) {
@@ -335,10 +338,9 @@ merge(Compressor.prototype, {
} else {
d.fixed = false;
}
} else {
mark_escaped(d, node, value, 0);
}
}
mark_escaped(d, node, value, 0);
}
if (node instanceof AST_SymbolCatch) {
node.definition().fixed = false;
@@ -389,7 +391,9 @@ merge(Compressor.prototype, {
d.fixed = false;
} else {
d.fixed = node;
loop_ids[d.id] = in_loop;
mark(d, true);
d.single_use = ref_once(d);
}
var save_ids = safe_ids;
safe_ids = Object.create(null);
@@ -542,6 +546,7 @@ merge(Compressor.prototype, {
}
return true;
}
return def.fixed instanceof AST_Defun;
}
function safe_to_assign(def, value) {
@@ -567,7 +572,7 @@ merge(Compressor.prototype, {
function reset_def(def) {
def.direct_access = false;
def.escaped = false;
if (def.scope.uses_eval) {
if (def.scope.uses_eval || def.scope.uses_with) {
def.fixed = false;
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
def.fixed = undefined;
@@ -579,8 +584,19 @@ merge(Compressor.prototype, {
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) {
return value && (value.is_constant() || value instanceof AST_Lambda);
if (!value) return false;
return value.is_constant()
|| value instanceof AST_Lambda
|| value instanceof AST_This;
}
function read_property(obj, key) {
@@ -608,10 +624,13 @@ merge(Compressor.prototype, {
|| !immutable
&& parent instanceof AST_Call
&& parent.expression === node
&& (!(value instanceof AST_Function) || value.contains_this())) {
&& (!(value instanceof AST_Function) || value.contains_this(parent))) {
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);
} 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) {
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
}
@@ -619,15 +638,19 @@ merge(Compressor.prototype, {
function mark_escaped(d, node, value, level) {
var parent = tw.parent(level);
if (value instanceof AST_Constant || value instanceof AST_Function) return;
if (value instanceof AST_Constant || value instanceof AST_ClassExpression) return;
if (level > 0 && value instanceof AST_Function) return;
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) {
d.escaped = true;
return;
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
} else if (parent instanceof AST_Array) {
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) {
value = read_property(value, parent.property);
mark_escaped(d, parent, value, level + 1);
@@ -811,6 +834,14 @@ merge(Compressor.prototype, {
|| compressor.option("unsafe") && global_names(this.name);
});
function drop_decl(def) {
def._eliminiated = (def._eliminiated || 0) + 1;
if (def.orig.length == def._eliminiated) {
def.scope.functions.del(def.name);
def.scope.variables.del(def.name);
}
}
function tighten_body(statements, compressor) {
var CHANGED, max_iter = 10;
do {
@@ -844,6 +875,7 @@ merge(Compressor.prototype, {
function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
if (scope.uses_eval || scope.uses_with) return statements;
var args;
var candidates = [];
var stat_index = statements.length;
while (--stat_index >= 0) {
@@ -864,7 +896,7 @@ merge(Compressor.prototype, {
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;
var abort = false, replaced = false, can_replace = !args || !hit;
var tt = new TreeTransformer(function(node, descend) {
if (abort) return node;
// Skip nodes before `candidate` as quickly as possible
@@ -891,7 +923,8 @@ merge(Compressor.prototype, {
return node;
}
// Replace variable with assignment when found
if (!(node instanceof AST_SymbolDeclaration)
if (can_replace
&& !(node instanceof AST_SymbolDeclaration)
&& !is_lhs(node, parent)
&& lhs.equivalent_to(node)) {
CHANGED = replaced = abort = true;
@@ -942,6 +975,12 @@ merge(Compressor.prototype, {
// Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
});
if (!can_replace) {
for (var j = compressor.self().argnames.lastIndexOf(candidate.__name || candidate.name) + 1; j < args.length; j++) {
args[j].transform(tt);
}
can_replace = true;
}
for (var i = stat_index; !abort && i < statements.length; i++) {
statements[i].transform(tt);
}
@@ -987,9 +1026,16 @@ merge(Compressor.prototype, {
})) {
var fn_strict = compressor.has_directive("use strict");
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
var len = fn.argnames.length;
args = iife.args.slice(len);
var names = Object.create(null);
for (var i = fn.argnames.length; --i >= 0;) {
for (var i = len; --i >= 0;) {
var sym = fn.argnames[i];
var arg = iife.args[i];
args.unshift(make_node(AST_VarDef, sym, {
name: sym,
value: arg
}));
if (sym.name in names) continue;
names[sym.name] = true;
if (sym instanceof AST_Expansion) {
@@ -1003,9 +1049,9 @@ merge(Compressor.prototype, {
elements: elements
})
}));
candidates[0].__name = sym;
}
} else {
var arg = iife.args[i];
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null;
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
@@ -1023,7 +1069,8 @@ merge(Compressor.prototype, {
candidates.push(expr);
} else if (expr instanceof AST_Sequence) {
expr.expressions.forEach(extract_candidates);
} else if (expr instanceof AST_Definitions) {
} else if (expr instanceof AST_Definitions
&& (compressor.option("unused") || !(expr instanceof AST_Const))) {
expr.definitions.forEach(function(var_def) {
if (var_def.value) candidates.push(var_def);
});
@@ -1037,7 +1084,8 @@ merge(Compressor.prototype, {
function get_lhs(expr) {
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
var def = expr.name.definition();
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
if (def.orig.length - (def._eliminiated || 0) > 1
&& !(expr.name instanceof AST_SymbolFunarg)
|| def.references.length == 1 && !compressor.exposed(def)) {
return make_node(AST_SymbolRef, expr.name, expr.name);
}
@@ -1047,6 +1095,10 @@ merge(Compressor.prototype, {
}
}
function get_rvalue(expr) {
return expr[expr instanceof AST_Assign ? "right" : "value"];
}
function get_lvalues(expr) {
var lvalues = Object.create(null);
if (expr instanceof AST_Unary) return lvalues;
@@ -1057,7 +1109,7 @@ merge(Compressor.prototype, {
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;
}
@@ -1083,10 +1135,12 @@ merge(Compressor.prototype, {
var found = false;
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
if (found) return node;
if (node === expr) {
if (node === expr || node.body === expr) {
found = true;
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;
}
@@ -1095,16 +1149,12 @@ merge(Compressor.prototype, {
case 0: return null;
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) {
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) {
@@ -2261,18 +2311,25 @@ merge(Compressor.prototype, {
}
def(AST_Node, return_false);
def(AST_Constant, return_true);
def(AST_Function, function(){
def(AST_Lambda, function(scope){
var self = this;
var result = true;
self.walk(new TreeWalker(function(node) {
if (!result) return true;
if (node instanceof AST_SymbolRef) {
var def = node.definition();
if (self.enclosed.indexOf(def) >= 0
&& self.variables.get(def.name) !== def) {
if (member(def, self.enclosed)
&& !self.variables.has(def.name)) {
if (scope) {
var scope_def = scope.find_variable(node);
if (def.undeclared ? !scope_def : scope_def === def) {
result = "f";
return true;
}
}
result = false;
return true;
}
return true;
}
}));
return result;
@@ -2353,7 +2410,7 @@ merge(Compressor.prototype, {
|| can_be_evicted_from_block(self.body[0])) {
return self.body[0];
}
break;
break;
case 0: return make_node(AST_EmptyStatement, self);
}
return self;
@@ -2389,75 +2446,80 @@ merge(Compressor.prototype, {
// this scope (not in nested scopes).
var scope = this;
var tw = new TreeWalker(function(node, descend){
if (node !== self) {
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
var in_export = tw.parent() instanceof AST_Export;
if (in_export || !drop_funcs && scope === self) {
var node_def = node.name.definition();
if (node_def.global && !(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
}
initializations.add(node.name.name, node);
return true; // don't go in nested scopes
}
if (node instanceof AST_Definitions && scope === self) {
var in_export = tw.parent() instanceof AST_Export;
node.definitions.forEach(function(def){
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(def.name.definition().id, def);
}
if (in_export || !drop_vars) {
def.name.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolDeclaration) {
var def = node.definition();
if ((in_export || def.global) && !(def.id in in_use_ids)) {
in_use_ids[def.id] = true;
in_use.push(def);
}
}
}));
}
if (def.value) {
if (def.name instanceof AST_Destructuring) {
var destructuring_cache = destructuring_value;
destructuring_value = def.value;
def.walk(tw);
destructuring_value = destructuring_cache;
} else {
initializations.add(def.name.name, def.value);
}
if (def.value.has_side_effects(compressor)) {
def.value.walk(tw);
}
}
});
return true;
}
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)) {
if (node instanceof AST_Assign) node.right.walk(tw);
return true;
}
if (node instanceof AST_SymbolRef) {
var node_def = node.definition();
if (!(node_def.id in in_use_ids)) {
if (node === self) return;
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
var in_export = tw.parent() instanceof AST_Export;
if (in_export || !drop_funcs && scope === self) {
var node_def = node.name.definition();
if (node_def.global && !(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
return true;
}
if (node instanceof AST_Scope) {
var save_scope = scope;
scope = node;
descend();
scope = save_scope;
return true;
}
if (node.destructuring && destructuring_value) {
initializations.add(node.name, destructuring_value);
initializations.add(node.name.name, node);
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) {
var in_export = tw.parent() instanceof AST_Export;
node.definitions.forEach(function(def){
if (def.name instanceof AST_SymbolVar) {
var_defs_by_id.add(def.name.definition().id, def);
}
if (in_export || !drop_vars) {
def.name.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolDeclaration) {
var def = node.definition();
if ((in_export || def.global) && !(def.id in in_use_ids)) {
in_use_ids[def.id] = true;
in_use.push(def);
}
}
}));
}
if (def.value) {
if (def.name instanceof AST_Destructuring) {
var destructuring_cache = destructuring_value;
destructuring_value = def.value;
def.walk(tw);
destructuring_value = destructuring_cache;
} else {
initializations.add(def.name.name, def.value);
}
if (def.value.has_side_effects(compressor)) {
def.value.walk(tw);
}
}
});
return true;
}
var sym;
if (scope === self
&& (sym = assign_as_unused(node)) instanceof AST_SymbolRef
&& !is_ref_of(node.left, AST_SymbolBlockDeclaration)
&& self.variables.get(sym.name) === sym.definition()) {
if (node instanceof AST_Assign) node.right.walk(tw);
return true;
}
if (node instanceof AST_SymbolRef) {
var node_def = node.definition();
if (!(node_def.id in in_use_ids)) {
in_use_ids[node_def.id] = true;
in_use.push(node_def);
}
return true;
}
if (node instanceof AST_Scope) {
var save_scope = scope;
scope = node;
descend();
scope = save_scope;
return true;
}
if (node.destructuring && destructuring_value) {
initializations.add(node.name, destructuring_value);
}
});
self.walk(tw);
@@ -2522,9 +2584,11 @@ merge(Compressor.prototype, {
}
}
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global;
var def = node.name.definition();
var keep = (def.id in in_use_ids) || !drop_funcs && def.global;
if (!keep) {
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
drop_decl(def);
return make_node(AST_EmptyStatement, node);
}
return node;
@@ -2549,7 +2613,7 @@ merge(Compressor.prototype, {
if (var_defs.length > 1 && !def.value) {
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
remove(var_defs, def);
remove(sym.orig, def.name);
drop_decl(sym);
return;
}
}
@@ -2582,7 +2646,7 @@ merge(Compressor.prototype, {
} else {
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
}
remove(sym.orig, def.name);
drop_decl(sym);
}
});
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
@@ -2591,7 +2655,7 @@ merge(Compressor.prototype, {
var def = tail.pop();
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
remove(var_defs, def);
remove(def.name.definition().orig, def.name);
drop_decl(def.name.definition());
side_effects.unshift(make_node(AST_Assign, def, {
operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name),
@@ -2623,8 +2687,7 @@ merge(Compressor.prototype, {
var def = assign_as_unused(node);
if (def instanceof AST_SymbolRef
&& !((def = def.definition()).id in in_use_ids)
&& (drop_vars || !def.global)
&& self.variables.get(def.name) === def) {
&& (drop_vars || !def.global)) {
if (node instanceof AST_Assign) {
return maintain_this_binding(parent, node, node.right.transform(tt));
}
@@ -2833,7 +2896,8 @@ merge(Compressor.prototype, {
self.variables.each(function(def, name) {
var_names[name] = true;
});
return self.transform(new TreeTransformer(function(node) {
var tt = new TreeTransformer(function(node) {
if (node instanceof AST_Definitions && tt.parent() instanceof AST_Export) return node;
if (node instanceof AST_VarDef) {
var sym = node.name, def, value;
if (sym.scope === self
@@ -2884,7 +2948,8 @@ merge(Compressor.prototype, {
var_names[name] = true;
return new_var;
}
}));
});
return self.transform(tt);
});
// drop_side_effect_free()
@@ -3440,7 +3505,7 @@ merge(Compressor.prototype, {
});
a.push(var_);
}
remove(def.name.definition().orig, def.name);
drop_decl(def.name.definition());
return a;
}, []);
if (assignments.length == 0) return null;
@@ -3723,6 +3788,7 @@ merge(Compressor.prototype, {
&& !exp.uses_arguments
&& !exp.uses_eval
&& (exp.body instanceof AST_Node || exp.body.length == 1)
&& !exp.contains_this()
&& all(exp.argnames, function(arg) {
if (arg instanceof AST_Expansion) return arg.expression.__unused;
return arg.__unused;
@@ -3737,23 +3803,6 @@ merge(Compressor.prototype, {
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) {
var args = self.args.concat(value);
return make_sequence(self, args).optimize(compressor);
@@ -4043,7 +4092,8 @@ merge(Compressor.prototype, {
function is_object(node) {
return node instanceof AST_Array
|| node instanceof AST_Lambda
|| node instanceof AST_Object;
|| node instanceof AST_Object
|| node instanceof AST_Class;
}
OPT(AST_Binary, function(self, compressor){
@@ -4423,6 +4473,17 @@ merge(Compressor.prototype, {
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){
var def = self.resolve_defines(compressor);
if (def) {
@@ -4448,49 +4509,68 @@ merge(Compressor.prototype, {
if (fixed instanceof AST_Defun) {
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
}
if (compressor.option("unused")
&& fixed
&& d.references.length == 1
&& (d.single_use || is_func_expr(fixed)
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
&& !d.scope.uses_eval
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
if (d.single_use && fixed instanceof AST_Function) {
if (!compressor.option("reduce_funcs") && d.scope !== self.scope) {
d.single_use = false;
} else if (d.escaped && d.scope !== self.scope || 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.name) scope.name.definition().single_use = false;
} while (scope = scope.parent_scope);
}
}
}
if (d.single_use && fixed) {
var value = fixed.optimize(compressor);
return value === fixed ? fixed.clone(true) : value;
}
if (compressor.option("evaluate") && fixed) {
if (d.should_replace === undefined) {
var init = fixed.evaluate(compressor);
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
init = make_node_from_constant(init, fixed);
var value_length = init.optimize(compressor).print_to_string().length;
var fn;
if (has_symbol_ref(fixed)) {
fn = function() {
var result = init.optimize(compressor);
return result === init ? result.clone(true) : result;
};
} else {
value_length = Math.min(value_length, fixed.print_to_string().length);
fn = function() {
var result = best_of_expression(init.optimize(compressor), fixed);
return result === init || result === fixed ? result.clone(true) : result;
};
}
var name_length = d.name.length;
var overhead = 0;
if (compressor.option("unused") && !compressor.exposed(d)) {
overhead = (name_length + 2 + value_length) / d.references.length;
}
d.should_replace = value_length <= name_length + overhead ? fn : false;
} else {
d.should_replace = false;
if (fixed && d.should_replace === undefined) {
var init;
if (fixed instanceof AST_This) {
if (!(d.orig[0] instanceof AST_SymbolFunarg)
&& all(d.references, function(ref) {
return d.scope === ref.scope;
})) {
init = fixed;
}
} else {
var ev = fixed.evaluate(compressor);
if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) {
init = make_node_from_constant(ev, fixed);
}
}
if (d.should_replace) {
return d.should_replace();
if (init) {
var value_length = init.optimize(compressor).print_to_string().length;
var fn;
if (has_symbol_ref(fixed)) {
fn = function() {
var result = init.optimize(compressor);
return result === init ? result.clone(true) : result;
};
} else {
value_length = Math.min(value_length, fixed.print_to_string().length);
fn = function() {
var result = best_of_expression(init.optimize(compressor), fixed);
return result === init || result === fixed ? result.clone(true) : result;
};
}
var name_length = d.name.length;
var overhead = 0;
if (compressor.option("unused") && !compressor.exposed(d)) {
overhead = (name_length + 2 + value_length) / d.references.length;
}
d.should_replace = value_length <= name_length + overhead ? fn : false;
} else {
d.should_replace = false;
}
}
if (d.should_replace) {
return d.should_replace();
}
}
return self;
@@ -4827,11 +4907,11 @@ merge(Compressor.prototype, {
}
}
if (is_lhs(self, compressor.parent())) return self;
if (compressor.option("properties") && key !== prop) {
var node = self.flatten_object(property, compressor);
if (node) {
expr = self.expression = node.expression;
prop = self.property = node.property;
if (key !== prop) {
var sub = self.flatten_object(property, compressor);
if (sub) {
expr = self.expression = sub.expression;
prop = self.property = sub.property;
}
}
if (compressor.option("properties") && compressor.option("side_effects")
@@ -4877,7 +4957,8 @@ merge(Compressor.prototype, {
return self;
});
AST_Lambda.DEFMETHOD("contains_this", function() {
AST_Lambda.DEFMETHOD("contains_this", function(grandparent) {
if (grandparent instanceof AST_New) return false;
var result;
var self = this;
self.walk(new TreeWalker(function(node) {
@@ -4889,6 +4970,7 @@ merge(Compressor.prototype, {
});
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
if (!compressor.option("properties")) return;
var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 6;
var expr = this.expression;
if (expr instanceof AST_Object) {
@@ -4902,7 +4984,7 @@ merge(Compressor.prototype, {
})) break;
var value = prop.value;
if ((value instanceof AST_Accessor || value instanceof AST_Function)
&& value.contains_this()) break;
&& value.contains_this(compressor.parent())) break;
return make_node(AST_Sub, this, {
expression: make_node(AST_Array, expr, {
elements: props.map(function(prop) {
@@ -4952,10 +5034,8 @@ merge(Compressor.prototype, {
}
}
if (is_lhs(self, compressor.parent())) return self;
if (compressor.option("properties")) {
var node = self.flatten_object(self.property, compressor);
if (node) return node.optimize(compressor);
}
var sub = self.flatten_object(self.property, compressor);
if (sub) return sub.optimize(compressor);
var ev = self.evaluate(compressor);
if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor);

View File

@@ -141,11 +141,9 @@ function minify(files, options) {
if (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 (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 (timings) timings.mangle = Date.now();
if (options.mangle) {
@@ -203,9 +201,9 @@ function minify(files, options) {
if (timings) {
timings.end = Date.now();
result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2),
compress: 1e-3 * (timings.scope2 - timings.compress),
parse: 1e-3 * (timings.compress - timings.parse),
compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),

View File

@@ -1361,6 +1361,7 @@ function OutputStream(options) {
self.exported_value.print(output);
} else if (self.exported_definition) {
self.exported_definition.print(output);
if (self.exported_definition instanceof AST_Definitions) return;
}
if (self.module_name) {
output.space();

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.1.6",
"version": "3.1.9",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -204,6 +204,7 @@ constant_join_3: {
for_loop: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
unused: true,
@@ -260,6 +261,7 @@ for_loop: {
index: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -278,6 +280,7 @@ index: {
length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -296,6 +299,7 @@ length: {
index_length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,

View File

@@ -288,6 +288,7 @@ issue_2105_1: {
ecma: 6,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
@@ -314,17 +315,12 @@ issue_2105_1: {
});
}
expect: {
(() => {
var quux = () => {
({
prop() {
console.log;
console.log("PASS");
};
return {
prop() {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=4"
@@ -335,6 +331,7 @@ issue_2105_2: {
collapse_vars: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -360,17 +357,12 @@ issue_2105_2: {
});
}
expect: {
(() => {
var quux = () => {
({
prop: () => {
console.log;
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -411,6 +403,7 @@ issue_2136_3: {
evaluate: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -438,6 +431,7 @@ call_args: {
ecma: 6,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -462,6 +456,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -509,6 +504,7 @@ issue_2084: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,

View File

@@ -141,6 +141,7 @@ async_inline: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,

View File

@@ -2,7 +2,8 @@ collapse_vars_side_effects_1: {
options = {
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,
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: {
function f1() {
@@ -150,7 +151,8 @@ collapse_vars_issue_721: {
options = {
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,
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: {
define(["require", "exports", 'handlebars'], function (require, exports, hb) {
@@ -216,7 +218,8 @@ collapse_vars_properties: {
options = {
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,
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: {
function f1(obj) {
@@ -243,7 +246,8 @@ collapse_vars_if: {
options = {
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,
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: {
function f1() {
@@ -293,7 +297,8 @@ collapse_vars_while: {
options = {
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,
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: {
function f1(y) {
@@ -712,7 +717,8 @@ collapse_vars_misc1: {
options = {
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,
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: {
function f0(o, a, h) {
@@ -789,7 +795,8 @@ collapse_vars_repeated: {
options = {
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,
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: {
function f1() {
@@ -831,7 +838,8 @@ collapse_vars_closures: {
options = {
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,
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: {
function constant_vars_can_be_replaced_in_any_scope() {
@@ -921,7 +929,8 @@ collapse_vars_try: {
options = {
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,
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: {
function f1() {
@@ -1118,7 +1127,8 @@ collapse_vars_constants: {
options = {
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,
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: {
function f1(x) {
@@ -1156,7 +1166,7 @@ collapse_vars_arguments: {
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,
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: {
var outer = function() {
@@ -1280,6 +1290,7 @@ collapse_vars_regexp: {
hoist_funs: true,
keep_fargs: true,
loops: false,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -1454,6 +1465,7 @@ issue_1562: {
options = {
collapse_vars: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -1487,6 +1499,7 @@ issue_1605_1: {
options = {
collapse_vars: true,
toplevel: false,
unused: true,
}
input: {
function foo(x) {
@@ -1509,6 +1522,7 @@ issue_1605_2: {
options = {
collapse_vars: true,
toplevel: "vars",
unused: true,
}
input: {
function foo(x) {
@@ -1636,6 +1650,7 @@ issue_1631_3: {
var_side_effects_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var print = console.log.bind(console);
@@ -1658,6 +1673,7 @@ var_side_effects_1: {
var_side_effects_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var print = console.log.bind(console);
@@ -1683,6 +1699,7 @@ var_side_effects_3: {
collapse_vars: true,
pure_getters: true,
unsafe: true,
unused: true,
}
input: {
var print = console.log.bind(console);
@@ -1705,6 +1722,7 @@ var_side_effects_3: {
reduce_vars_assign: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -1727,6 +1745,7 @@ reduce_vars_assign: {
iife_1: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -1747,6 +1766,7 @@ iife_1: {
iife_2: {
options = {
collapse_vars: true,
reduce_funcs: false,
reduce_vars: false,
toplevel: true,
unused: false,
@@ -1758,6 +1778,7 @@ iife_2: {
}(foo);
}
expect: {
var foo;
!function(x) {
console.log(x);
}(bar());
@@ -2044,6 +2065,7 @@ ref_scope: {
chained_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 2;
@@ -2060,6 +2082,7 @@ chained_1: {
chained_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a;
@@ -2160,6 +2183,7 @@ inner_lvalues: {
double_def: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = x, a = a && y;
@@ -2174,6 +2198,7 @@ double_def: {
toplevel_single_reference: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a;
@@ -2183,9 +2208,10 @@ toplevel_single_reference: {
}
}
expect: {
var a;
for (var b in x)
for (var b in x) {
var a;
b(a = b);
}
}
}
@@ -2193,6 +2219,7 @@ unused_orig: {
options = {
collapse_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2215,10 +2242,11 @@ unused_orig: {
expect: {
var a = 1;
console.log(function(b) {
var a;
var c = b;
for (var d in c)
for (var d in c) {
var a;
return --b + (a = c[0]);
}
a && a.NaN;
}([2]), a);
}
@@ -2230,6 +2258,7 @@ issue_315: {
collapse_vars: true,
evaluate: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
unused: true,
@@ -2565,7 +2594,10 @@ issue_2250_1: {
options = {
collapse_vars: true,
conditionals: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f(x) {
@@ -2604,9 +2636,11 @@ issue_2250_2: {
options = {
collapse_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
{
@@ -2632,6 +2666,7 @@ issue_2250_2: {
issue_2298: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2997,6 +3032,7 @@ issue_2364_5: {
evaluate: true,
pure_getters: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -3163,6 +3199,7 @@ pure_getters_chain: {
options = {
collapse_vars: true,
pure_getters: true,
unused: true,
}
input: {
function o(t, r) {
@@ -3183,6 +3220,7 @@ pure_getters_chain: {
conditional_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(a, b) {
@@ -3207,6 +3245,7 @@ conditional_1: {
conditional_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(a, b) {
@@ -3223,3 +3262,141 @@ conditional_2: {
}
expect_stdout: "5 5"
}
issue_2425_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect_stdout: "15"
}
issue_2425_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b, c) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b, c) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect_stdout: "15"
}
issue_2425_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = 8;
(function(b, b) {
b.toString();
})(--a, a |= 10);
console.log(a);
}
expect: {
var a = 8;
(function(b, b) {
(a |= 10).toString();
})(--a);
console.log(a);
}
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_2453: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
function log(n) {
console.log(n);
}
const a = 42;
log(a);
}
expect: {
function log(n) {
console.log(n);
}
const a = 42;
log(a);
}
expect_stdout: "42"
}

View File

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

View File

@@ -12,6 +12,7 @@ issue_1191: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -44,6 +45,7 @@ issue_1194: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -72,6 +74,7 @@ issue_1396: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -143,6 +146,7 @@ regexp_literal_not_const: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {

View File

@@ -202,6 +202,7 @@ dead_code_const_declaration: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
};
input: {
@@ -229,6 +230,7 @@ dead_code_const_annotation: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
toplevel : true,
};
@@ -281,6 +283,7 @@ dead_code_const_annotation_complex_scope: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
toplevel : true,
};
@@ -439,6 +442,7 @@ global_timeout_and_interval_symbols: {
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
@@ -470,6 +474,7 @@ issue_2233_2: {
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,

View File

@@ -262,6 +262,7 @@ destructuring_dont_evaluate_with_undefined_as_default_assignment: {
reduce_vars: {
options = {
reduce_funcs: true,
reduce_vars: true,
}
input: {

View File

@@ -733,6 +733,7 @@ drop_value: {
const_assign: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -785,6 +786,7 @@ issue_1539: {
vardef_value: {
options = {
keep_fnames: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -846,6 +848,7 @@ assign_chain: {
issue_1583: {
options = {
keep_fargs: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -1200,6 +1203,7 @@ var_catch_toplevel: {
options = {
conditionals: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -1294,11 +1298,12 @@ issue_2063: {
}
}
issue_2105: {
issue_2105_1: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -1324,17 +1329,51 @@ issue_2105: {
});
}
expect: {
(function() {
var quux = function() {
({
prop: function() {
console.log;
console.log("PASS");
};
return {
prop: function() {
console.log;
quux();
}
}).prop();
}
expect_stdout: "PASS"
}
issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
properties: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
};
})().prop();
return bar;
} );
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
@@ -1389,6 +1428,7 @@ issue_2136_3: {
evaluate: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,

View File

@@ -345,6 +345,7 @@ unsafe_constant: {
unsafe_object: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -373,6 +374,7 @@ unsafe_object: {
unsafe_object_nested: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -401,6 +403,7 @@ unsafe_object_nested: {
unsafe_object_complex: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -429,6 +432,7 @@ unsafe_object_complex: {
unsafe_object_repeated: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -457,6 +461,7 @@ unsafe_object_repeated: {
unsafe_object_accessor: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
}
@@ -757,6 +762,7 @@ call_args: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -779,6 +785,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -1109,6 +1116,7 @@ Infinity_NaN_undefined_LHS: {
issue_1964_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: false,
unused: true,
@@ -1138,6 +1146,7 @@ issue_1964_1: {
issue_1964_2: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: true,
unused: true,
@@ -1294,6 +1303,7 @@ issue_2231_2: {
self_comparison_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -1314,6 +1324,7 @@ self_comparison_2: {
evaluate: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,

View File

@@ -124,6 +124,7 @@ async_func: {
issue_2134_1: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -141,6 +142,7 @@ issue_2134_1: {
issue_2134_2: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -250,3 +252,13 @@ dynamic_import: {
r.foo();
}
}
trailing_comma: {
beautify = {
beautify: true,
}
input: {
export const a = 1;
}
expect_exact: "export const a = 1;"
}

View File

@@ -19,6 +19,7 @@ iifes_returning_constants_keep_fargs_true: {
booleans : true,
if_return : true,
join_vars : true,
reduce_funcs : true,
reduce_vars : true,
cascade : true,
inline : true,
@@ -55,6 +56,7 @@ iifes_returning_constants_keep_fargs_false: {
booleans : true,
if_return : true,
join_vars : true,
reduce_funcs : true,
reduce_vars : true,
cascade : true,
inline : true,
@@ -101,6 +103,7 @@ issue_1841_1: {
options = {
keep_fargs: false,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -127,6 +130,7 @@ issue_1841_2: {
options = {
keep_fargs: false,
pure_getters: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -154,6 +158,7 @@ function_returning_constant_literal: {
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -305,6 +310,7 @@ issue_2084: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -340,6 +346,7 @@ issue_2084: {
issue_2097: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -508,3 +515,42 @@ issue_2114_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

@@ -736,6 +736,7 @@ object_spread_unsafe: {
evaluate: true,
join_vars: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -903,6 +904,7 @@ issue_2349b: {
inline: true,
passes: 3,
properties: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
side_effects: true,

View File

@@ -3,6 +3,7 @@ issue_2377_1: {
evaluate: true,
inline: true,
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -35,6 +36,7 @@ issue_2377_2: {
inline: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -66,6 +68,7 @@ issue_2377_3: {
inline: true,
hoist_props: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -92,6 +95,7 @@ issue_2377_3: {
direct_access_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -120,6 +124,7 @@ direct_access_1: {
direct_access_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -143,6 +148,7 @@ direct_access_2: {
direct_access_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -163,6 +169,7 @@ direct_access_3: {
single_use: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -187,6 +194,7 @@ single_use: {
name_collision_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
@@ -224,6 +232,7 @@ name_collision_1: {
name_collision_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
@@ -257,6 +266,7 @@ name_collision_2: {
name_collision_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
@@ -293,6 +303,7 @@ contains_this_1: {
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -318,6 +329,7 @@ contains_this_2: {
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -345,6 +357,7 @@ contains_this_3: {
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -369,3 +382,169 @@ contains_this_3: {
}
expect_stdout: "1 1 true"
}
hoist_class: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function run(c, v) {
return new c(v).value;
}
var o = {
p: class Foo {
constructor(value) {
this.value = value * 10;
}
},
x: 1,
y: 2,
};
console.log(o.p.name, o.p === o.p, run(o.p, o.x), run(o.p, o.y));
}
expect: {
function run(c, v) {
return new c(v).value;
}
var o_p = class Foo {
constructor(value) {
this.value = 10 * value;
}
};
console.log(o_p.name, true, run(o_p, 1), run(o_p, 2));
}
node_version: ">=6"
expect_stdout: "Foo true 10 20"
}
hoist_class_with_new: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
p: class Foo {
constructor(value) {
this.value = value * 10;
}
},
x: 1,
y: 2,
};
console.log(o.p.name, o.p === o.p, new o.p(o.x).value, new o.p(o.y).value);
}
expect: {
// FIXME: class `o.p` not hoisted due to `new`
var o = {
p: class Foo {
constructor(value) {
this.value = 10 * value;
}
},
x: 1,
y: 2
};
console.log(o.p.name, o.p == o.p, new o.p(o.x).value, new o.p(o.y).value);
}
node_version: ">=6"
expect_stdout: "Foo true 10 20"
}
hoist_function_with_call: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
p: function Foo(value) {
return 10 * value;
},
x: 1,
y: 2
};
console.log(o.p.name, o.p === o.p, o.p(o.x), o.p(o.y));
}
expect: {
var o_p = function Foo(value){
return 10 * value
};
console.log(o_p.name, true, o_p(1), o_p(2));
}
expect_stdout: "Foo true 10 20"
}
new_this: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
f: function(a) {
this.b = a;
}
};
console.log(new o.f(o.a).b, o.b);
}
expect: {
console.log(new function(a) {
this.b = a;
}(1).b, 2);
}
expect_stdout: "1 2"
}
issue_2462: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
export const Foo = {
a: 1,
b: () => 2
};
}
expect: {
export const Foo = {
a: 1,
b: () => 2
};
}
}

View File

@@ -14,6 +14,7 @@ const_declaration: {
const_pragma: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};
@@ -29,6 +30,7 @@ const_pragma: {
not_const: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -177,6 +177,7 @@ export_mangle_2: {
export_mangle_3: {
options = {
collapse_vars: true,
unused: true,
}
mangle = {
toplevel: true,
@@ -195,6 +196,7 @@ export_mangle_3: {
export_mangle_4: {
options = {
collapse_vars: true,
unused: true,
}
mangle = {
toplevel: true,

View File

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

View File

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

View File

@@ -940,6 +940,7 @@ methods_keep_quoted_from_dead_code: {
dead_code: true,
ecma: 6,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
@@ -1085,6 +1086,7 @@ lhs_prop_2: {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -1131,6 +1133,7 @@ prop_side_effects_1: {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -1167,6 +1170,7 @@ prop_side_effects_2: {
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -1282,3 +1286,22 @@ computed_property: {
]
node_version: ">=4"
}
new_this: {
options = {
properties: true,
side_effects: true,
}
input: {
new {
f: function(a) {
this.a = a;
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -162,6 +162,7 @@ var VALUES = [
'"object"',
'"number"',
'"function"',
'this',
];
var BINARY_OPS_NO_COMMA = [
@@ -349,10 +350,10 @@ function createParams() {
return params.join(', ');
}
function createArgs() {
function createArgs(recurmax, stmtDepth, canThrow) {
var args = [];
for (var n = rng(4); --n >= 0;) {
args.push(createValue());
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
}
return args.join(', ');
}
@@ -390,9 +391,10 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
VAR_NAMES.length = namesLenBefore;
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');';
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s;
// avoid "function statements" (decl inside statements)
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name;
s += '(' + createArgs(recurmax, stmtDepth, canThrow) + ');';
return s;
}
@@ -626,6 +628,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
case p++:
case p++:
return createValue();
case p++:
case p++:
return getVarName();
case p++:
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
case p++: