Compare commits
24 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53600e9869 | ||
|
|
7dea749f58 | ||
|
|
8ca49155a8 | ||
|
|
b95e3338d9 | ||
|
|
e40a0ee9c6 | ||
|
|
0a3fac6e68 | ||
|
|
cb62bd98d3 | ||
|
|
9f7d1f7ac6 | ||
|
|
f30790b11b | ||
|
|
5205dbcbf4 | ||
|
|
3ff625de7e | ||
|
|
4832bc5d88 | ||
|
|
7f342cb3e3 | ||
|
|
05e7d34ed4 | ||
|
|
ef74f2eaaf | ||
|
|
96082f7a9b | ||
|
|
86607156e3 | ||
|
|
0fe259e9c5 | ||
|
|
a53784e0c5 | ||
|
|
a3b8dec347 | ||
|
|
49ce573971 | ||
|
|
8701a99a15 | ||
|
|
1476c78b53 | ||
|
|
cb6a92892f |
185
lib/compress.js
185
lib/compress.js
@@ -326,6 +326,7 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
def.fixed = false;
|
||||
}
|
||||
def.recursive_refs = 0;
|
||||
def.references = [];
|
||||
def.should_replace = undefined;
|
||||
def.single_use = undefined;
|
||||
@@ -383,7 +384,7 @@ merge(Compressor.prototype, {
|
||||
return compressor.option("unused")
|
||||
&& !def.scope.uses_eval
|
||||
&& !def.scope.uses_with
|
||||
&& def.references.length == 1
|
||||
&& def.references.length - def.recursive_refs == 1
|
||||
&& tw.loop_ids[def.id] === tw.in_loop;
|
||||
}
|
||||
|
||||
@@ -482,6 +483,10 @@ merge(Compressor.prototype, {
|
||||
def(AST_Arrow, mark_func_expr);
|
||||
def(AST_Assign, function(tw) {
|
||||
var node = this;
|
||||
if (node.left instanceof AST_Destructuring) {
|
||||
node.left.walk(suppressor);
|
||||
return;
|
||||
}
|
||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||
var d = node.left.definition();
|
||||
if (safe_to_assign(tw, d, node.right)
|
||||
@@ -665,7 +670,9 @@ merge(Compressor.prototype, {
|
||||
d.fixed = false;
|
||||
} else if (d.fixed) {
|
||||
value = this.fixed_value();
|
||||
if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
||||
if (value instanceof AST_Lambda && recursive_ref(tw, d)) {
|
||||
d.recursive_refs++;
|
||||
} else if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
||||
d.single_use = value instanceof AST_Lambda
|
||||
|| value instanceof AST_Class
|
||||
|| d.scope === this.scope && value.is_constant_expression();
|
||||
@@ -705,7 +712,7 @@ merge(Compressor.prototype, {
|
||||
var node = this;
|
||||
if (node.name instanceof AST_Destructuring) {
|
||||
node.name.walk(suppressor);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
var d = node.name.definition();
|
||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
||||
@@ -1816,15 +1823,8 @@ merge(Compressor.prototype, {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
switch (this.operator) {
|
||||
case "&&":
|
||||
return this.left._dot_throw(compressor);
|
||||
case "||":
|
||||
return this.left._dot_throw(compressor)
|
||||
&& this.right._dot_throw(compressor);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator == "="
|
||||
@@ -2809,15 +2809,15 @@ merge(Compressor.prototype, {
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (node === self) return;
|
||||
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
||||
var node_def = node.name.definition();
|
||||
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);
|
||||
initializations.add(node_def.id, node);
|
||||
return true; // don't go in nested scopes
|
||||
}
|
||||
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||
@@ -2847,7 +2847,7 @@ merge(Compressor.prototype, {
|
||||
def.walk(tw);
|
||||
destructuring_value = destructuring_cache;
|
||||
} else {
|
||||
initializations.add(def.name.name, def.value);
|
||||
initializations.add(def.name.definition().id, def.value);
|
||||
}
|
||||
if (def.value.has_side_effects(compressor)) {
|
||||
def.value.walk(tw);
|
||||
@@ -2866,13 +2866,10 @@ merge(Compressor.prototype, {
|
||||
// initialization code to figure out if it uses other
|
||||
// symbols (that may not be in_use).
|
||||
tw = new TreeWalker(scan_ref_scoped);
|
||||
for (var i = 0; i < in_use.length; ++i) {
|
||||
in_use[i].orig.forEach(function(decl){
|
||||
// undeclared globals will be instanceof AST_SymbolRef
|
||||
var init = initializations.get(decl.name);
|
||||
if (init) init.forEach(function(init){
|
||||
init.walk(tw);
|
||||
});
|
||||
for (var i = 0; i < in_use.length; i++) {
|
||||
var init = initializations.get(in_use[i].id);
|
||||
if (init) init.forEach(function(init) {
|
||||
init.walk(tw);
|
||||
});
|
||||
}
|
||||
// pass 3: we should drop declarations not in_use
|
||||
@@ -3938,9 +3935,10 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
||||
fn = fn.fixed_value();
|
||||
}
|
||||
var is_func = fn instanceof AST_Lambda;
|
||||
if (compressor.option("unused")
|
||||
&& simple_args
|
||||
&& is_func_expr(fn)
|
||||
&& is_func
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.uses_eval) {
|
||||
var pos = 0, last = 0;
|
||||
@@ -4127,7 +4125,7 @@ merge(Compressor.prototype, {
|
||||
if (func instanceof AST_SymbolRef) {
|
||||
func = func.fixed_value();
|
||||
}
|
||||
if (func instanceof AST_Function && !func.contains_this()) {
|
||||
if (func instanceof AST_Lambda && !func.contains_this()) {
|
||||
return make_sequence(this, [
|
||||
self.args[0],
|
||||
make_node(AST_Call, self, {
|
||||
@@ -4204,7 +4202,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
var stat = is_func_expr(fn) && fn.body;
|
||||
var stat = is_func && fn.body;
|
||||
if (stat instanceof AST_Node) {
|
||||
stat = make_node(AST_Return, stat, {
|
||||
value: stat
|
||||
@@ -4219,8 +4217,8 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (is_func_expr(fn) && !fn.is_generator && !fn.async) {
|
||||
var def, scope, value;
|
||||
if (is_func && !fn.is_generator && !fn.async) {
|
||||
var def, value, scope, level = -1;
|
||||
if (compressor.option("inline")
|
||||
&& simple_args
|
||||
&& !fn.uses_arguments
|
||||
@@ -4233,9 +4231,9 @@ merge(Compressor.prototype, {
|
||||
&& fn.is_constant_expression(exp.scope))
|
||||
&& !self.pure
|
||||
&& !fn.contains_this()
|
||||
&& (scope = can_flatten_args(fn))
|
||||
&& can_flatten_args(fn)
|
||||
&& (value = flatten_body(stat))) {
|
||||
var expressions = flatten_args(fn, scope);
|
||||
var expressions = flatten_args(fn);
|
||||
expressions.push(value.clone(true));
|
||||
return make_sequence(self, expressions).optimize(compressor);
|
||||
}
|
||||
@@ -4268,34 +4266,48 @@ merge(Compressor.prototype, {
|
||||
return self;
|
||||
|
||||
function can_flatten_args(fn) {
|
||||
var scope, level = 0;
|
||||
var catches = Object.create(null);
|
||||
var catches = Object.create(null), defs;
|
||||
do {
|
||||
scope = compressor.parent(level++);
|
||||
if (scope instanceof AST_SymbolRef) {
|
||||
scope = scope.fixed_value();
|
||||
} else if (scope instanceof AST_Catch) {
|
||||
scope = compressor.parent(++level);
|
||||
if (scope instanceof AST_Catch) {
|
||||
catches[scope.argname.name] = true;
|
||||
} else if (scope instanceof AST_IterationStatement) {
|
||||
defs = [];
|
||||
} else if (scope instanceof AST_SymbolRef) {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope));
|
||||
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
||||
return all(fn.argnames, function(arg) {
|
||||
if (arg instanceof AST_Expansion) return arg.expression.__unused;
|
||||
return arg.__unused
|
||||
|| safe_to_inject
|
||||
&& !catches[arg.name]
|
||||
&& !identifier_atom(arg.name)
|
||||
&& !scope.var_names()[arg.name];
|
||||
}) && scope;
|
||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg instanceof AST_DefaultAssign) {
|
||||
if (arg.left.__unused) continue;
|
||||
return false;
|
||||
}
|
||||
if (arg instanceof AST_Destructuring) return false;
|
||||
if (arg instanceof AST_Expansion) {
|
||||
if (arg.expression.__unused) continue;
|
||||
return false;
|
||||
}
|
||||
if (arg.__unused) continue;
|
||||
if (!safe_to_inject
|
||||
|| catches[arg.name]
|
||||
|| identifier_atom(arg.name)
|
||||
|| scope.var_names()[arg.name]) {
|
||||
return false;
|
||||
}
|
||||
if (defs) defs.push(arg.definition());
|
||||
}
|
||||
return !defs || defs.length == 0 || !is_reachable(stat, defs);
|
||||
}
|
||||
|
||||
function flatten_args(fn, scope) {
|
||||
function flatten_args(fn) {
|
||||
var decls = [];
|
||||
var expressions = [];
|
||||
for (var len = fn.argnames.length, i = len; --i >= 0;) {
|
||||
var name = fn.argnames[i];
|
||||
var value = self.args[i];
|
||||
if (name.__unused || name instanceof AST_Expansion) {
|
||||
if (name.__unused || !name.name) {
|
||||
if (value || expressions.length) {
|
||||
expressions.unshift(value || make_node(AST_Undefined, self));
|
||||
}
|
||||
@@ -4323,8 +4335,7 @@ merge(Compressor.prototype, {
|
||||
expressions.push(self.args[i]);
|
||||
}
|
||||
if (decls.length) {
|
||||
for (i = 0; compressor.parent(i) !== scope;) i++;
|
||||
i = scope.body.indexOf(compressor.parent(i - 1)) + 1;
|
||||
i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
|
||||
scope.body.splice(i, 0, make_node(AST_Var, fn, {
|
||||
definitions: decls
|
||||
}));
|
||||
@@ -4965,23 +4976,18 @@ merge(Compressor.prototype, {
|
||||
&& is_lhs(self, compressor.parent()) !== self) {
|
||||
var d = self.definition();
|
||||
var fixed = self.fixed_value();
|
||||
if (fixed instanceof AST_DefClass) {
|
||||
d.fixed = fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||
}
|
||||
if (fixed instanceof AST_Defun) {
|
||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
if (d.single_use && (is_func_expr(fixed) || fixed instanceof AST_ClassExpression)) {
|
||||
var single_use = d.single_use;
|
||||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
|
||||
if (d.scope !== self.scope
|
||||
&& (!compressor.option("reduce_funcs") && is_func_expr(fixed)
|
||||
&& (!compressor.option("reduce_funcs") && fixed instanceof AST_Lambda
|
||||
|| d.escaped == 1
|
||||
|| fixed.inlined)) {
|
||||
d.single_use = false;
|
||||
single_use = false;
|
||||
} else if (recursive_ref(compressor, d)) {
|
||||
d.single_use = false;
|
||||
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") {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
var scope = self.scope;
|
||||
do {
|
||||
if (scope instanceof AST_Defun || is_func_expr(scope)) {
|
||||
@@ -4991,9 +4997,36 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d.single_use && fixed) {
|
||||
var value = fixed.optimize(compressor);
|
||||
return value === fixed ? fixed.clone(true) : value;
|
||||
if (single_use && fixed) {
|
||||
if (fixed instanceof AST_DefClass) {
|
||||
fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||
}
|
||||
if (fixed instanceof AST_Defun) {
|
||||
fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
var value;
|
||||
if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
|
||||
value = fixed.clone(true);
|
||||
var defun_def = value.name.definition();
|
||||
var lambda_def = value.variables.get(value.name.name);
|
||||
var name = lambda_def && lambda_def.orig[0];
|
||||
if (!(name instanceof AST_SymbolLambda)) {
|
||||
name = make_node(AST_SymbolLambda, value.name, value.name);
|
||||
name.scope = value;
|
||||
value.name = name;
|
||||
lambda_def = value.def_function(name);
|
||||
}
|
||||
value.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
|
||||
node.thedef = lambda_def;
|
||||
lambda_def.references.push(node);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
value = fixed.optimize(compressor);
|
||||
if (value === fixed) value = fixed.clone(true);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (fixed && d.should_replace === undefined) {
|
||||
var init;
|
||||
@@ -5115,18 +5148,42 @@ merge(Compressor.prototype, {
|
||||
return self;
|
||||
});
|
||||
|
||||
function is_reachable(node, defs) {
|
||||
var reachable = false;
|
||||
var find_ref = new TreeWalker(function(node) {
|
||||
if (reachable) return true;
|
||||
if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
|
||||
return reachable = true;
|
||||
}
|
||||
});
|
||||
var scan_scope = new TreeWalker(function(node) {
|
||||
if (reachable) return true;
|
||||
if (node instanceof AST_Scope) {
|
||||
var parent = scan_scope.parent();
|
||||
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
||||
node.walk(find_ref);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
node.walk(scan_scope);
|
||||
return reachable;
|
||||
}
|
||||
|
||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
||||
OPT(AST_Assign, function(self, compressor){
|
||||
var def;
|
||||
if (compressor.option("dead_code")
|
||||
&& self.left instanceof AST_SymbolRef
|
||||
&& self.left.definition().scope === compressor.find_parent(AST_Lambda)) {
|
||||
&& (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) {
|
||||
var level = 0, node, parent = self;
|
||||
do {
|
||||
node = parent;
|
||||
parent = compressor.parent(level++);
|
||||
if (parent instanceof AST_Exit) {
|
||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||
if (is_reachable(self, [ def ])) break;
|
||||
if (self.operator == "=") return self.right;
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: self.operator.slice(0, -1),
|
||||
|
||||
@@ -730,15 +730,9 @@ function OutputStream(options) {
|
||||
return p instanceof AST_PropAccess && p.expression === this;
|
||||
});
|
||||
|
||||
PARENS(AST_ClassExpression, function(output){
|
||||
return output.parent() instanceof AST_SimpleStatement;
|
||||
});
|
||||
|
||||
// same goes for an object literal, because otherwise it would be
|
||||
// interpreted as a block of code.
|
||||
PARENS(AST_Object, function(output){
|
||||
return first_in_statement(output);
|
||||
});
|
||||
PARENS([ AST_ClassExpression, AST_Object ], first_in_statement);
|
||||
|
||||
PARENS(AST_Unary, function(output){
|
||||
var p = output.parent();
|
||||
|
||||
25
lib/parse.js
25
lib/parse.js
@@ -934,10 +934,15 @@ function parse($TEXT, options) {
|
||||
|
||||
function expect(punc) { return expect_token("punc", punc); };
|
||||
|
||||
function has_newline_before(token) {
|
||||
return token.nlb || !all(token.comments_before, function(comment) {
|
||||
return !comment.nlb;
|
||||
});
|
||||
}
|
||||
|
||||
function can_insert_semicolon() {
|
||||
return !options.strict && (
|
||||
S.token.nlb || is("eof") || is("punc", "}")
|
||||
);
|
||||
return !options.strict
|
||||
&& (is("eof") || is("punc", "}") || has_newline_before(S.token));
|
||||
};
|
||||
|
||||
function is_in_generator() {
|
||||
@@ -985,10 +990,10 @@ function parse($TEXT, options) {
|
||||
if (S.in_directives) {
|
||||
var token = peek();
|
||||
if (S.token.raw.indexOf("\\") == -1
|
||||
&& (token.nlb
|
||||
|| is_token(token, "eof")
|
||||
|| is_token(token, "punc", ";")
|
||||
|| is_token(token, "punc", "}"))) {
|
||||
&& (is_token(token, "punc", ";")
|
||||
|| is_token(token, "punc", "}")
|
||||
|| has_newline_before(token)
|
||||
|| is_token(token, "eof"))) {
|
||||
S.input.add_directive(S.token.value);
|
||||
} else {
|
||||
S.in_directives = false;
|
||||
@@ -1111,7 +1116,7 @@ function parse($TEXT, options) {
|
||||
|
||||
case "throw":
|
||||
next();
|
||||
if (S.token.nlb)
|
||||
if (has_newline_before(S.token))
|
||||
croak("Illegal newline after 'throw'");
|
||||
var value = expression(true);
|
||||
semicolon();
|
||||
@@ -1287,7 +1292,7 @@ function parse($TEXT, options) {
|
||||
};
|
||||
|
||||
var arrow_function = function(start, argnames, is_async) {
|
||||
if (S.token.nlb) {
|
||||
if (has_newline_before(S.token)) {
|
||||
croak("Unexpected newline before arrow (=>)");
|
||||
}
|
||||
|
||||
@@ -2738,7 +2743,7 @@ function parse($TEXT, options) {
|
||||
return ex;
|
||||
}
|
||||
var val = expr_atom(allow_calls, allow_arrows);
|
||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
|
||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) {
|
||||
if (val instanceof AST_Arrow) unexpected();
|
||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||
val.start = start;
|
||||
|
||||
@@ -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.3.0",
|
||||
"version": "3.3.3",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ var urls = [
|
||||
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
|
||||
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
|
||||
"https://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.js",
|
||||
];
|
||||
var results = {};
|
||||
var remaining = 2 * urls.length;
|
||||
|
||||
@@ -4180,10 +4180,9 @@ recursive_function_replacement: {
|
||||
console.log(f(c));
|
||||
}
|
||||
expect: {
|
||||
function f(n) {
|
||||
return x(y(f(n)));
|
||||
}
|
||||
console.log(f(c));
|
||||
console.log(function n(o) {
|
||||
return x(y(n(o)));
|
||||
}(c));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,3 +1047,30 @@ issue_2597: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2666: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
return a = {
|
||||
p: function() {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
}
|
||||
console.log(typeof f().p());
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
return a = {
|
||||
p: function() {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
}
|
||||
console.log(typeof f().p());
|
||||
}
|
||||
expect_stdout: "object"
|
||||
}
|
||||
|
||||
@@ -1786,3 +1786,112 @@ issue_2418_5: {
|
||||
(function f() {});
|
||||
}
|
||||
}
|
||||
|
||||
defun_lambda_same_name: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(n) {
|
||||
return n ? n * f(n - 1) : 1;
|
||||
}
|
||||
console.log(function f(n) {
|
||||
return n ? n * f(n - 1) : 1;
|
||||
}(5));
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(n) {
|
||||
return n ? n * f(n - 1) : 1;
|
||||
}(5));
|
||||
}
|
||||
expect_stdout: "120"
|
||||
}
|
||||
|
||||
issue_2660_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 2;
|
||||
function f(b) {
|
||||
return b && f() || a--;
|
||||
}
|
||||
f(1);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 2;
|
||||
(function f(b) {
|
||||
return b && f() || a--;
|
||||
})(1);
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2660_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f(b) {
|
||||
b && f();
|
||||
--a, a.toString();
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
(function f(b) {
|
||||
b && f(),
|
||||
(--a).toString();
|
||||
})(),
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_2665: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
typeofs: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function g() {
|
||||
a-- && g();
|
||||
}
|
||||
typeof h == "function" && h();
|
||||
function h() {
|
||||
typeof g == "function" && g();
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function g() {
|
||||
a-- && g();
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "-1"
|
||||
}
|
||||
|
||||
@@ -1378,11 +1378,10 @@ issue_2630_3: {
|
||||
expect: {
|
||||
var x = 2, a = 1;
|
||||
(function() {
|
||||
function f1(a) {
|
||||
(function f1(a) {
|
||||
f2();
|
||||
--x >= 0 && f1({});
|
||||
}
|
||||
f1(a++);
|
||||
})(a++);
|
||||
function f2() {
|
||||
a++;
|
||||
}
|
||||
@@ -1456,3 +1455,319 @@ issue_2630_5: {
|
||||
}
|
||||
expect_stdout: "155"
|
||||
}
|
||||
|
||||
issue_2647_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(n, o = "FAIL") {
|
||||
console.log(n);
|
||||
})("PASS");
|
||||
(function(n, o = "PASS") {
|
||||
console.log(o);
|
||||
})("FAIL");
|
||||
(function(o = "PASS") {
|
||||
console.log(o);
|
||||
})();
|
||||
(function(n, {o = "FAIL"}) {
|
||||
console.log(n);
|
||||
})("PASS", {});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
(function(n, o = "PASS") {
|
||||
console.log(o);
|
||||
})();
|
||||
(function(o = "PASS") {
|
||||
console.log(o);
|
||||
})();
|
||||
(function(n, {o = "FAIL"}) {
|
||||
console.log("PASS");
|
||||
})(0, {});
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2647_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function foo(x) {
|
||||
return x.toUpperCase();
|
||||
}
|
||||
console.log((() => foo("pass"))());
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("pass".toUpperCase());
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_2647_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function foo(x) {
|
||||
return x.toUpperCase();
|
||||
}
|
||||
console.log((() => {
|
||||
return foo("pass");
|
||||
})());
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("pass".toUpperCase());
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
recursive_inline_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
h();
|
||||
}
|
||||
function g(a) {
|
||||
a();
|
||||
}
|
||||
function h(b) {
|
||||
g();
|
||||
if (b) x();
|
||||
}
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
recursive_inline_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(n) {
|
||||
return n ? n * f(n - 1) : 1;
|
||||
}
|
||||
console.log(f(5));
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(n) {
|
||||
return n ? n * f(n - 1) : 1;
|
||||
}(5));
|
||||
}
|
||||
expect_stdout: "120"
|
||||
}
|
||||
|
||||
issue_2657: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
console.log(function f() {
|
||||
return h;
|
||||
function g(b) {
|
||||
return b || b();
|
||||
}
|
||||
function h(a) {
|
||||
g(a);
|
||||
return a;
|
||||
}
|
||||
}()(42));
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log(function(a) {
|
||||
return b = a, b || b(), a;
|
||||
var b;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2663_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var i, o = {};
|
||||
function createFn(j) {
|
||||
return function() {
|
||||
console.log(j);
|
||||
};
|
||||
}
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
o[i] = createFn(i);
|
||||
for (i in o)
|
||||
o[i]();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var i, o = {};
|
||||
function createFn(j) {
|
||||
return function() {
|
||||
console.log(j);
|
||||
};
|
||||
}
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
o[i] = createFn(i);
|
||||
for (i in o)
|
||||
o[i]();
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2663_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var i;
|
||||
function fn(j) {
|
||||
return function() {
|
||||
console.log(j);
|
||||
}();
|
||||
}
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
fn(i);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var i;
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
j = i, console.log(j);
|
||||
var j;
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2663_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function () {
|
||||
var outputs = [
|
||||
{ type: 0, target: null, eventName: "ngSubmit", propName: null },
|
||||
{ type: 0, target: null, eventName: "submit", propName: null },
|
||||
{ type: 0, target: null, eventName: "reset", propName: null },
|
||||
];
|
||||
function listenToElementOutputs(outputs) {
|
||||
var handlers = [];
|
||||
for (var i = 0; i < outputs.length; i++) {
|
||||
var output = outputs[i];
|
||||
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||
handlers.push(handleEventClosure)
|
||||
}
|
||||
var target, name;
|
||||
return handlers;
|
||||
}
|
||||
function renderEventHandlerClosure(eventName) {
|
||||
return function () {
|
||||
return console.log(eventName);
|
||||
};
|
||||
}
|
||||
listenToElementOutputs(outputs).forEach(function (handler) {
|
||||
return handler()
|
||||
});
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
function renderEventHandlerClosure(eventName) {
|
||||
return function() {
|
||||
return console.log(eventName);
|
||||
};
|
||||
}
|
||||
(function(outputs) {
|
||||
var handlers = [];
|
||||
for (var i = 0; i < outputs.length; i++) {
|
||||
var output = outputs[i];
|
||||
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||
handlers.push(handleEventClosure);
|
||||
}
|
||||
return handlers;
|
||||
})([ {
|
||||
type: 0,
|
||||
target: null,
|
||||
eventName: "ngSubmit",
|
||||
propName: null
|
||||
}, {
|
||||
type: 0,
|
||||
target: null,
|
||||
eventName: "submit",
|
||||
propName: null
|
||||
}, {
|
||||
type: 0,
|
||||
target: null,
|
||||
eventName: "reset",
|
||||
propName: null
|
||||
} ]).forEach(function(handler) {
|
||||
return handler();
|
||||
});
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"ngSubmit",
|
||||
"submit",
|
||||
"reset",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1197,3 +1197,18 @@ class_method_using_arguments: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2676: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
class A {}
|
||||
A.a = 42;
|
||||
}
|
||||
expect: {
|
||||
(class {}).a = 42;
|
||||
}
|
||||
}
|
||||
|
||||
33
test/compress/issue-2652.js
Normal file
33
test/compress/issue-2652.js
Normal file
@@ -0,0 +1,33 @@
|
||||
insert_semicolon: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
comments: "all",
|
||||
}
|
||||
input: {
|
||||
var a
|
||||
/* foo */ var b
|
||||
}
|
||||
expect_exact: [
|
||||
"var a",
|
||||
"/* foo */;",
|
||||
"",
|
||||
"var b;",
|
||||
]
|
||||
}
|
||||
|
||||
unary_postfix: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
comments: "all",
|
||||
}
|
||||
input: {
|
||||
a
|
||||
/* foo */++b
|
||||
}
|
||||
expect_exact: [
|
||||
"a",
|
||||
"/* foo */;",
|
||||
"",
|
||||
"++b;",
|
||||
]
|
||||
}
|
||||
@@ -735,3 +735,35 @@ issue_2313_7: {
|
||||
expect_stdout: "2 1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2678: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, c = "FAIL";
|
||||
(function f() {
|
||||
(a-- && f()).p;
|
||||
return {
|
||||
get p() {
|
||||
c = "PASS";
|
||||
}
|
||||
};
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, c = "FAIL";
|
||||
(function f() {
|
||||
(a-- && f()).p;
|
||||
return {
|
||||
get p() {
|
||||
c = "PASS";
|
||||
}
|
||||
};
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1355,10 +1355,9 @@ defun_inline_1: {
|
||||
function f() {
|
||||
return function(b) {
|
||||
return b;
|
||||
}(2) + h();
|
||||
function h() {
|
||||
}(2) + function h() {
|
||||
return h();
|
||||
}
|
||||
}();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1382,12 +1381,11 @@ defun_inline_2: {
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function h() {
|
||||
return h();
|
||||
}
|
||||
return function(b) {
|
||||
return b;
|
||||
}(2) + h();
|
||||
}(2) + function h() {
|
||||
return h();
|
||||
}();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5446,3 +5444,44 @@ issue_2598: {
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_2669: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
let foo;
|
||||
console.log(([ foo ] = [ "PASS" ]) && foo);
|
||||
}
|
||||
expect: {
|
||||
let foo;
|
||||
console.log(([ foo ] = [ "PASS" ]) && foo);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2670: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
const obj = {};
|
||||
obj.prop = "PASS";
|
||||
const {prop: value} = obj;
|
||||
console.log(value);
|
||||
}
|
||||
expect: {
|
||||
const obj = {};
|
||||
obj.prop = "PASS";
|
||||
const {prop: value} = obj;
|
||||
console.log(value);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -329,7 +329,8 @@ function createTopLevelCode() {
|
||||
rng(2) == 0
|
||||
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
||||
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
||||
'console.log(null, a, b, c);' // preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||
// preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||
'console.log(null, a, b, c, Infinity, NaN, undefined);'
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
@@ -635,6 +636,8 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
case p++:
|
||||
return getVarName();
|
||||
case p++:
|
||||
return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||
case p++:
|
||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||
case p++:
|
||||
|
||||
Reference in New Issue
Block a user