Merge branch 'master' into harmony-v3.1.10

This commit is contained in:
alexlamsl
2017-11-19 14:34:27 +08:00
10 changed files with 935 additions and 232 deletions

View File

@@ -15,6 +15,8 @@
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
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.**

View File

@@ -706,11 +706,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
`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_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
used as constant values.
@@ -907,6 +908,9 @@ can pass additional arguments that control the code output:
- `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
specifies an (orientative) line width that the beautifier will try to
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 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 options = {
compress: false,

View File

@@ -389,15 +389,15 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda);
var AST_Function = DEFNODE("Function", null, {
var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Arrow = DEFNODE("Arrow", null, {
var AST_Arrow = DEFNODE("Arrow", "inlined", {
$documentation: "An ES6 Arrow function ((a) => b)"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
var AST_Defun = DEFNODE("Defun", "inlined", {
$documentation: "A function definition"
}, AST_Lambda);

View File

@@ -386,6 +386,7 @@ merge(Compressor.prototype, {
}
}
if (node instanceof AST_Defun) {
node.inlined = false;
var d = node.name.definition();
if (compressor.exposed(d) || safe_to_read(d)) {
d.fixed = false;
@@ -402,6 +403,7 @@ merge(Compressor.prototype, {
return true;
}
if (is_func_expr(node)) {
node.inlined = false;
push();
var iife;
if (!node.name
@@ -835,8 +837,8 @@ merge(Compressor.prototype, {
});
function drop_decl(def) {
def._eliminiated = (def._eliminiated || 0) + 1;
if (def.orig.length == def._eliminiated) {
def.eliminated++;
if (def.orig.length == def.eliminated) {
def.scope.functions.del(def.name);
def.scope.variables.del(def.name);
}
@@ -878,6 +880,115 @@ merge(Compressor.prototype, {
var args;
var candidates = [];
var stat_index = statements.length;
var scanner = new TreeTransformer(function(node, descend) {
if (abort) return node;
// Skip nodes before `candidate` as quickly as possible
if (!hit) {
if (node === candidate) {
hit = true;
return node;
}
return;
}
// Stop immediately if these node types are encountered
var parent = scanner.parent();
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|| node instanceof AST_Await
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|| node instanceof AST_Debugger
|| node instanceof AST_Destructuring
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|| node instanceof AST_SymbolRef && !node.is_declared(compressor)
|| node instanceof AST_Try
|| node instanceof AST_With
|| parent instanceof AST_For && node !== parent.init) {
abort = true;
return node;
}
// Replace variable with assignment when found
if (can_replace
&& !(node instanceof AST_SymbolDeclaration)
&& lhs.equivalent_to(node)) {
if (is_lhs(node, parent)) {
if (candidate.multiple) replaced++;
return node;
}
CHANGED = abort = true;
replaced++;
compressor.info("Collapsing {name} [{file}:{line},{col}]", {
name: node.print_to_string(),
file: node.start.file,
line: node.start.line,
col: node.start.col
});
if (candidate instanceof AST_UnaryPostfix) {
return make_node(AST_UnaryPrefix, candidate, candidate);
}
if (candidate instanceof AST_VarDef) {
if (candidate.multiple) {
abort = false;
return node;
}
var def = candidate.name.definition();
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
def.replaced++;
return maintain_this_binding(parent, node, candidate.value);
}
return make_node(AST_Assign, candidate, {
operator: "=",
left: make_node(AST_SymbolRef, candidate.name, candidate.name),
right: candidate.value
});
}
candidate.write_only = false;
return candidate;
}
// These node types have child nodes that execute sequentially,
// but are otherwise not safe to scan into or beyond them.
var sym;
if (node instanceof AST_Call
|| node instanceof AST_Exit
|| node instanceof AST_PropAccess
&& (side_effects || node.expression.may_throw_on_access(compressor))
|| node instanceof AST_SymbolRef
&& (lvalues[node.name]
|| side_effects && !references_in_scope(node.definition()))
|| (sym = lhs_or_def(node))
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|| (side_effects || !replace_all)
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|| parent instanceof AST_Case
|| parent instanceof AST_Conditional
|| parent instanceof AST_If)) {
if (!(node instanceof AST_Scope)) descend(node, scanner);
abort = true;
return node;
}
// Skip (non-executed) functions and (leading) default case in switch statements
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());
@@ -893,96 +1004,34 @@ merge(Compressor.prototype, {
// 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 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 = false, can_replace = !args || !hit;
var tt = new TreeTransformer(function(node, descend) {
if (abort) return node;
// Skip nodes before `candidate` as quickly as possible
if (!hit) {
if (node === candidate) {
hit = true;
return node;
}
return;
}
// Stop immediately if these node types are encountered
var parent = tt.parent();
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|| node instanceof AST_Await
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|| node instanceof AST_Debugger
|| node instanceof AST_Destructuring
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|| node instanceof AST_SymbolRef && !node.is_declared(compressor)
|| node instanceof AST_Try
|| node instanceof AST_With
|| parent instanceof AST_For && node !== parent.init) {
abort = true;
return node;
}
// Replace variable with assignment when found
if (can_replace
&& !(node instanceof AST_SymbolDeclaration)
&& !is_lhs(node, parent)
&& lhs.equivalent_to(node)) {
CHANGED = replaced = abort = true;
compressor.info("Collapsing {name} [{file}:{line},{col}]", {
name: node.print_to_string(),
file: node.start.file,
line: node.start.line,
col: node.start.col
});
if (candidate instanceof AST_UnaryPostfix) {
return make_node(AST_UnaryPrefix, candidate, candidate);
}
if (candidate instanceof AST_VarDef) {
var def = candidate.name.definition();
if (def.references.length == 1 && !compressor.exposed(def)) {
return maintain_this_binding(parent, node, candidate.value);
}
return make_node(AST_Assign, candidate, {
operator: "=",
left: make_node(AST_SymbolRef, candidate.name, candidate.name),
right: candidate.value
});
}
candidate.write_only = false;
return candidate;
}
// These node types have child nodes that execute sequentially,
// but are otherwise not safe to scan into or beyond them.
var sym;
if (node instanceof AST_Call
|| node instanceof AST_Exit
|| node instanceof AST_PropAccess
&& (side_effects || node.expression.may_throw_on_access(compressor))
|| node instanceof AST_SymbolRef
&& (lvalues[node.name]
|| side_effects && !references_in_scope(node.definition()))
|| (sym = lhs_or_def(node))
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|| (side_effects || !one_off)
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|| parent instanceof AST_Case
|| parent instanceof AST_Conditional
|| parent instanceof AST_If)) {
if (!(node instanceof AST_Scope)) descend(node, tt);
abort = true;
return node;
}
// Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
});
var abort = false, replaced = 0, can_replace = !args || !hit;
if (!can_replace) {
for (var j = compressor.self().argnames.lastIndexOf(candidate.__name || candidate.name) + 1; j < args.length; j++) {
args[j].transform(tt);
for (var j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) {
args[j].transform(scanner);
}
can_replace = true;
}
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);
}
@@ -1025,7 +1074,7 @@ merge(Compressor.prototype, {
return !(arg instanceof AST_Expansion);
})) {
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;
args = iife.args.slice(len);
var names = Object.create(null);
@@ -1081,12 +1130,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) {
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
var def = expr.name.definition();
if (def.orig.length - (def._eliminiated || 0) > 1
&& !(expr.name instanceof AST_SymbolFunarg)
|| def.references.length == 1 && !compressor.exposed(def)) {
var declared = def.orig.length - def.eliminated;
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);
}
} else {
@@ -2655,12 +2714,14 @@ 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);
drop_decl(def.name.definition());
side_effects.unshift(make_node(AST_Assign, def, {
operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name),
right: def.value
}));
def = def.name.definition();
drop_decl(def);
def.replaced--;
}
}
if (head.length > 0 || tail.length > 0) {
@@ -2885,17 +2946,29 @@ merge(Compressor.prototype, {
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){
var self = this;
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 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;
});
var tt = new TreeTransformer(function(node) {
if (node instanceof AST_Definitions && tt.parent() instanceof AST_Export) return node;
if (node instanceof AST_VarDef) {
@@ -2904,6 +2977,7 @@ merge(Compressor.prototype, {
&& !(def = sym.definition()).escaped
&& !def.single_use
&& !def.direct_access
&& !top_retain(def)
&& (value = sym.fixed_value()) === node.value
&& value instanceof AST_Object) {
var defs = new Dictionary();
@@ -2935,17 +3009,13 @@ merge(Compressor.prototype, {
}
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, {
name: name,
name: self.make_var_name(sym.name + "_" + key),
scope: self
});
var def = self.def_variable(new_var);
defs.set(key, def);
self.enclosed.push(def);
var_names[name] = true;
return new_var;
}
});
@@ -3569,136 +3639,139 @@ merge(Compressor.prototype, {
self.args.length = last;
}
if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) {
switch (exp.name) {
case "Array":
if (self.args.length != 1) {
return make_node(AST_Array, self, {
elements: self.args
}).optimize(compressor);
}
break;
case "Object":
if (self.args.length == 0) {
return make_node(AST_Object, self, {
properties: []
});
}
break;
case "String":
if (self.args.length == 0) return make_node(AST_String, self, {
value: ""
});
if (self.args.length <= 1) return make_node(AST_Binary, self, {
left: self.args[0],
operator: "+",
right: make_node(AST_String, self, { value: "" })
if (is_undeclared_ref(exp)) switch (exp.name) {
case "Array":
if (self.args.length != 1) {
return make_node(AST_Array, self, {
elements: self.args
}).optimize(compressor);
break;
case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, {
value: 0
});
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "+"
}).optimize(compressor);
case "Boolean":
if (self.args.length == 0) return make_node(AST_False, self);
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "!"
}),
operator: "!"
}).optimize(compressor);
break;
case "Symbol":
// Symbol's argument is only used for debugging.
self.args = [];
return self;
}
}
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
return make_node(AST_Binary, self, {
break;
case "Object":
if (self.args.length == 0) {
return make_node(AST_Object, self, {
properties: []
});
}
break;
case "String":
if (self.args.length == 0) return make_node(AST_String, self, {
value: ""
});
if (self.args.length <= 1) return make_node(AST_Binary, self, {
left: self.args[0],
operator: "+",
right: make_node(AST_String, self, { value: "" })
}).optimize(compressor);
break;
case "Number":
if (self.args.length == 0) return make_node(AST_Number, self, {
value: 0
});
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "+"
}).optimize(compressor);
case "Boolean":
if (self.args.length == 0) return make_node(AST_False, self);
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
expression: make_node(AST_UnaryPrefix, self, {
expression: self.args[0],
operator: "!"
}),
operator: "!"
}).optimize(compressor);
break;
case "Symbol":
// Symbol's argument is only used for debugging.
self.args = [];
return self;
} else if (exp instanceof AST_Dot) switch(exp.property) {
case "toString":
if (self.args.length == 0) return make_node(AST_Binary, self, {
left: make_node(AST_String, self, { value: "" }),
operator: "+",
right: exp.expression
}).optimize(compressor);
}
else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
var separator;
if (self.args.length > 0) {
separator = self.args[0].evaluate(compressor);
if (separator === self.args[0]) break EXIT; // not a constant
}
var elements = [];
var consts = [];
for (var i = 0, len = exp.expression.elements.length; i < len; i++) {
var el = exp.expression.elements[i];
if (el instanceof AST_Expansion) break EXIT;
var value = el.evaluate(compressor);
if (value !== el) {
consts.push(value);
} else {
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
value: consts.join(separator)
}));
consts.length = 0;
break;
case "join":
if (exp.expression instanceof AST_Array) EXIT: {
var separator;
if (self.args.length > 0) {
separator = self.args[0].evaluate(compressor);
if (separator === self.args[0]) break EXIT; // not a constant
}
var elements = [];
var consts = [];
for (var i = 0, len = exp.expression.elements.length; i < len; i++) {
var el = exp.expression.elements[i];
if (el instanceof AST_Expansion) break EXIT;
var value = el.evaluate(compressor);
if (value !== el) {
consts.push(value);
} else {
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
value: consts.join(separator)
}));
consts.length = 0;
}
elements.push(el);
}
elements.push(el);
}
}
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
value: consts.join(separator)
}));
}
if (elements.length == 0) return make_node(AST_String, self, { value: "" });
if (elements.length == 1) {
if (elements[0].is_string(compressor)) {
return elements[0];
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
value: consts.join(separator)
}));
}
return make_node(AST_Binary, elements[0], {
operator : "+",
left : make_node(AST_String, self, { value: "" }),
right : elements[0]
});
}
if (separator == "") {
var first;
if (elements[0].is_string(compressor)
|| elements[1].is_string(compressor)) {
first = elements.shift();
} else {
first = make_node(AST_String, self, { value: "" });
}
return elements.reduce(function(prev, el){
return make_node(AST_Binary, el, {
if (elements.length == 0) return make_node(AST_String, self, { value: "" });
if (elements.length == 1) {
if (elements[0].is_string(compressor)) {
return elements[0];
}
return make_node(AST_Binary, elements[0], {
operator : "+",
left : prev,
right : el
left : make_node(AST_String, self, { value: "" }),
right : elements[0]
});
}, first).optimize(compressor);
}
if (separator == "") {
var first;
if (elements[0].is_string(compressor)
|| elements[1].is_string(compressor)) {
first = elements.shift();
} else {
first = make_node(AST_String, self, { value: "" });
}
return elements.reduce(function(prev, el){
return make_node(AST_Binary, el, {
operator : "+",
left : prev,
right : el
});
}, first).optimize(compressor);
}
// need this awkward cloning to not affect original element
// best_of will decide which one to get through.
var node = self.clone();
node.expression = node.expression.clone();
node.expression.expression = node.expression.expression.clone();
node.expression.expression.elements = elements;
return best_of(compressor, self, node);
}
// need this awkward cloning to not affect original element
// best_of will decide which one to get through.
var node = self.clone();
node.expression = node.expression.clone();
node.expression.expression = node.expression.expression.clone();
node.expression.expression.elements = elements;
return best_of(compressor, self, node);
}
else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") {
var arg = self.args[0];
var index = arg ? arg.evaluate(compressor) : 0;
if (index !== arg) {
return make_node(AST_Sub, exp, {
expression: exp.expression,
property: make_node_from_constant(index | 0, arg || exp)
}).optimize(compressor);
break;
case "charAt":
if (exp.expression.is_string(compressor)) {
var arg = self.args[0];
var index = arg ? arg.evaluate(compressor) : 0;
if (index !== arg) {
return make_node(AST_Sub, exp, {
expression: exp.expression,
property: make_node_from_constant(index | 0, arg || exp)
}).optimize(compressor);
}
}
break;
}
}
if (compressor.option("unsafe_Func")
@@ -4510,16 +4583,21 @@ merge(Compressor.prototype, {
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
}
if (d.single_use && fixed instanceof AST_Function) {
if (!compressor.option("reduce_funcs") && d.scope !== self.scope) {
if (d.scope !== self.scope
&& (!compressor.option("reduce_funcs")
|| d.escaped
|| fixed.inlined)) {
d.single_use = false;
} else if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) {
} 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.name) scope.name.definition().single_use = false;
if (scope instanceof AST_Defun || scope instanceof AST_Function) {
scope.inlined = true;
}
} while (scope = scope.parent_scope);
}
}

View File

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

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

View File

@@ -3400,3 +3400,483 @@ issue_2453: {
}
expect_stdout: "42"
}
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

@@ -548,3 +548,92 @@ issue_2462: {
};
}
}
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

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