Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5beb7e4797 | ||
|
|
46caaa82ba | ||
|
|
5d258259a4 | ||
|
|
14c35739dd | ||
|
|
f5ceff6e4b | ||
|
|
4d6771b9b1 | ||
|
|
d17191111a | ||
|
|
0ff607cb80 | ||
|
|
1988495d71 | ||
|
|
fdc10086da | ||
|
|
746f5f6c62 | ||
|
|
d83d3d741a | ||
|
|
99ac73a635 | ||
|
|
a2e4c2fd97 | ||
|
|
94785e8e14 | ||
|
|
4dbdac9c31 | ||
|
|
78c8efd851 | ||
|
|
af310ba2d0 | ||
|
|
2f3930d1b9 | ||
|
|
d1a78920d9 | ||
|
|
d9cd3d33c8 | ||
|
|
22b47cdd63 | ||
|
|
4cf612dc9f | ||
|
|
a19d31dd33 |
@@ -87,6 +87,7 @@ a double dash to prevent input files being used as option arguments:
|
||||
`wrap_iife` Wrap IIFEs in parenthesis. Note: you may
|
||||
want to disable `negate_iife` under
|
||||
compressor options.
|
||||
-O, --output-opts [options] Specify output options (`beautify` disabled by default).
|
||||
-o, --output <file> Output file path (default STDOUT). Specify `ast` or
|
||||
`spidermonkey` to write UglifyJS or SpiderMonkey AST
|
||||
as JSON to STDOUT respectively.
|
||||
|
||||
@@ -36,6 +36,7 @@ program.option("-c, --compress [options]", "Enable compressor/specify compressor
|
||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
|
||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
|
||||
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
|
||||
program.option("-O, --output-opts [options]", "Output options (beautify disabled).", parse_js());
|
||||
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||
@@ -59,7 +60,7 @@ if (program.configFile) {
|
||||
if (options.mangle && options.mangle.properties && options.mangle.properties.regex) {
|
||||
options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, {
|
||||
expression: true
|
||||
}).getValue();
|
||||
}).value;
|
||||
}
|
||||
}
|
||||
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
@@ -93,6 +94,10 @@ if (program.beautify) {
|
||||
options.output.beautify = true;
|
||||
}
|
||||
}
|
||||
if (program.outputOpts) {
|
||||
if (program.beautify) fatal("--beautify cannot be used with --output-opts");
|
||||
options.output = typeof program.outputOpts == "object" ? program.outputOpts : {};
|
||||
}
|
||||
if (program.comments) {
|
||||
if (typeof options.output != "object") options.output = {};
|
||||
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
|
||||
@@ -370,7 +375,7 @@ function parse_js(flag) {
|
||||
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
|
||||
|
||||
function to_string(value) {
|
||||
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({
|
||||
return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
|
||||
quote_keys: true
|
||||
});
|
||||
}
|
||||
|
||||
11
lib/ast.js
11
lib/ast.js
@@ -618,7 +618,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
|
||||
getProperty: function() {
|
||||
var p = this.property;
|
||||
if (p instanceof AST_Constant) {
|
||||
return p.getValue();
|
||||
return p.value;
|
||||
}
|
||||
if (p instanceof AST_UnaryPrefix
|
||||
&& p.operator == "void"
|
||||
@@ -824,9 +824,6 @@ var AST_This = DEFNODE("This", null, {
|
||||
|
||||
var AST_Constant = DEFNODE("Constant", null, {
|
||||
$documentation: "Base class for all constants",
|
||||
getValue: function() {
|
||||
return this.value;
|
||||
}
|
||||
});
|
||||
|
||||
var AST_String = DEFNODE("String", "value quote", {
|
||||
@@ -967,11 +964,13 @@ TreeWalker.prototype = {
|
||||
in_boolean_context: function() {
|
||||
var self = this.self();
|
||||
for (var i = 0, p; p = this.parent(i); i++) {
|
||||
if (p instanceof AST_SimpleStatement
|
||||
|| p instanceof AST_Conditional && p.condition === self
|
||||
if (p instanceof AST_Conditional && p.condition === self
|
||||
|| p instanceof AST_DWLoop && p.condition === self
|
||||
|| p instanceof AST_For && p.condition === self
|
||||
|| p instanceof AST_If && p.condition === self
|
||||
|| p instanceof AST_Return && p.in_bool
|
||||
|| p instanceof AST_Sequence && p.tail_node() !== self
|
||||
|| p instanceof AST_SimpleStatement
|
||||
|| p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
|
||||
return true;
|
||||
}
|
||||
|
||||
420
lib/compress.js
420
lib/compress.js
@@ -209,6 +209,7 @@ merge(Compressor.prototype, {
|
||||
if (is_scope) {
|
||||
node.hoist_properties(this);
|
||||
node.hoist_declarations(this);
|
||||
node.process_boolean_returns(this);
|
||||
}
|
||||
// Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
|
||||
// would call AST_Node.transform() if a different instance of AST_Node is
|
||||
@@ -241,7 +242,7 @@ merge(Compressor.prototype, {
|
||||
return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string();
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
|
||||
AST_Scope.DEFMETHOD("process_expression", function(insert, transform) {
|
||||
var self = this;
|
||||
var tt = new TreeTransformer(function(node) {
|
||||
if (insert && node instanceof AST_SimpleStatement) {
|
||||
@@ -250,13 +251,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
if (!insert && node instanceof AST_Return) {
|
||||
if (compressor) {
|
||||
var value = node.value && node.value.drop_side_effect_free(compressor, true);
|
||||
return value ? make_node(AST_SimpleStatement, node, {
|
||||
body: value
|
||||
}) : make_node(AST_EmptyStatement, node);
|
||||
}
|
||||
return make_node(AST_SimpleStatement, node, {
|
||||
return transform ? transform(node) : make_node(AST_SimpleStatement, node, {
|
||||
body: node.value || make_node(AST_UnaryPrefix, node, {
|
||||
operator: "void",
|
||||
expression: make_node(AST_Number, node, {
|
||||
@@ -361,6 +356,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function reset_def(tw, compressor, def) {
|
||||
def.assignments = 0;
|
||||
def.bool_fn = 0;
|
||||
def.chained = false;
|
||||
def.cross_loop = false;
|
||||
def.direct_access = false;
|
||||
@@ -596,14 +592,22 @@ merge(Compressor.prototype, {
|
||||
def(AST_Call, function(tw, descend) {
|
||||
tw.find_parent(AST_Scope).may_call_this();
|
||||
var exp = this.expression;
|
||||
if (!(exp instanceof AST_SymbolRef)) return;
|
||||
var def = exp.definition();
|
||||
if (!(def.fixed instanceof AST_Defun)) return;
|
||||
var defun = mark_defun(tw, def);
|
||||
if (!defun) return;
|
||||
descend();
|
||||
defun.walk(tw);
|
||||
return true;
|
||||
if (exp instanceof AST_SymbolRef) {
|
||||
var def = exp.definition();
|
||||
if (this.TYPE == "Call" && tw.in_boolean_context()) def.bool_fn++;
|
||||
if (!(def.fixed instanceof AST_Defun)) return;
|
||||
var defun = mark_defun(tw, def);
|
||||
if (!defun) return;
|
||||
descend();
|
||||
defun.walk(tw);
|
||||
return true;
|
||||
} else if (this.TYPE == "Call"
|
||||
&& exp instanceof AST_Assign
|
||||
&& exp.operator == "="
|
||||
&& exp.left instanceof AST_SymbolRef
|
||||
&& tw.in_boolean_context()) {
|
||||
exp.left.definition().bool_fn++;
|
||||
}
|
||||
});
|
||||
def(AST_Case, function(tw) {
|
||||
push(tw);
|
||||
@@ -1352,7 +1356,10 @@ merge(Compressor.prototype, {
|
||||
return node.operator != "=" && lhs.equivalent_to(node.left);
|
||||
}
|
||||
if (node instanceof AST_Call) {
|
||||
return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression);
|
||||
if (!(lhs instanceof AST_PropAccess)) return false;
|
||||
if (!lhs.equivalent_to(node.expression)) return false;
|
||||
var rhs = get_rvalue(candidate);
|
||||
return !(rhs instanceof AST_Function && !rhs.contains_this());
|
||||
}
|
||||
if (node instanceof AST_Debugger) return true;
|
||||
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
||||
@@ -1363,7 +1370,7 @@ merge(Compressor.prototype, {
|
||||
if (replace_all) return false;
|
||||
return node instanceof AST_SymbolRef
|
||||
&& !node.is_declared(compressor)
|
||||
&& !(parent instanceof AST_Assign && parent.left === node);
|
||||
&& !(parent instanceof AST_Assign && parent.operator == "=" && parent.left === node);
|
||||
}
|
||||
|
||||
function in_conditional(node, parent) {
|
||||
@@ -2017,9 +2024,10 @@ merge(Compressor.prototype, {
|
||||
|
||||
if (stat instanceof AST_If && stat.body instanceof AST_Return) {
|
||||
var value = stat.body.value;
|
||||
var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool;
|
||||
//---
|
||||
// pretty silly case, but:
|
||||
// if (foo()) return; return; ==> foo(); return;
|
||||
// if (foo()) return; return; => foo(); return;
|
||||
if (!value && !stat.alternative
|
||||
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
|
||||
CHANGED = true;
|
||||
@@ -2029,8 +2037,8 @@ merge(Compressor.prototype, {
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||
if (value && !stat.alternative && next instanceof AST_Return && next.value) {
|
||||
// if (foo()) return x; return y; => return foo() ? x : y;
|
||||
if ((in_bool || value) && !stat.alternative && next instanceof AST_Return) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = next;
|
||||
@@ -2039,21 +2047,18 @@ merge(Compressor.prototype, {
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||
if (value && !stat.alternative
|
||||
&& (!next && in_lambda && multiple_if_returns
|
||||
|| next instanceof AST_Return)) {
|
||||
// if (foo()) return x; [ return ; ] => return foo() ? x : undefined;
|
||||
if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
|
||||
CHANGED = true;
|
||||
stat = stat.clone();
|
||||
stat.alternative = next || make_node(AST_Return, stat, {
|
||||
stat.alternative = make_node(AST_Return, stat, {
|
||||
value: null
|
||||
});
|
||||
statements.splice(i, 1, stat.transform(compressor));
|
||||
if (next) statements.splice(j, 1);
|
||||
continue;
|
||||
}
|
||||
//---
|
||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||
// if (a) return b; if (c) return d; e; => return a ? b : c ? d : void e;
|
||||
//
|
||||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||
// however, with sequences on this helps producing slightly better output for
|
||||
@@ -2872,9 +2877,11 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function convert_to_predicate(obj) {
|
||||
var map = Object.create(null);
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
obj[key] = makePredicate(obj[key]);
|
||||
map[key] = makePredicate(obj[key]);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
AST_Lambda.DEFMETHOD("first_statement", function() {
|
||||
@@ -2897,7 +2904,7 @@ merge(Compressor.prototype, {
|
||||
"toString",
|
||||
"valueOf",
|
||||
];
|
||||
var native_fns = {
|
||||
var native_fns = convert_to_predicate({
|
||||
Array: [
|
||||
"indexOf",
|
||||
"join",
|
||||
@@ -2933,9 +2940,8 @@ merge(Compressor.prototype, {
|
||||
"toUpperCase",
|
||||
"trim",
|
||||
].concat(object_fns),
|
||||
};
|
||||
convert_to_predicate(native_fns);
|
||||
var static_fns = {
|
||||
});
|
||||
var static_fns = convert_to_predicate({
|
||||
Array: [
|
||||
"isArray",
|
||||
],
|
||||
@@ -2975,8 +2981,7 @@ merge(Compressor.prototype, {
|
||||
String: [
|
||||
"fromCharCode",
|
||||
],
|
||||
};
|
||||
convert_to_predicate(static_fns);
|
||||
});
|
||||
|
||||
// methods to evaluate a constant expression
|
||||
(function(def) {
|
||||
@@ -3014,7 +3019,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Lambda, return_this);
|
||||
def(AST_Node, return_this);
|
||||
def(AST_Constant, function() {
|
||||
return this.getValue();
|
||||
return this.value;
|
||||
});
|
||||
def(AST_Function, function(compressor) {
|
||||
if (compressor.option("unsafe")) {
|
||||
@@ -3199,7 +3204,7 @@ merge(Compressor.prototype, {
|
||||
Object: Object,
|
||||
String: String,
|
||||
};
|
||||
var static_values = {
|
||||
var static_values = convert_to_predicate({
|
||||
Math: [
|
||||
"E",
|
||||
"LN10",
|
||||
@@ -3217,8 +3222,7 @@ merge(Compressor.prototype, {
|
||||
"NEGATIVE_INFINITY",
|
||||
"POSITIVE_INFINITY",
|
||||
],
|
||||
};
|
||||
convert_to_predicate(static_values);
|
||||
});
|
||||
var regexp_props = makePredicate("global ignoreCase multiline source");
|
||||
def(AST_PropAccess, function(compressor, cached, depth) {
|
||||
if (compressor.option("unsafe")) {
|
||||
@@ -3636,7 +3640,7 @@ merge(Compressor.prototype, {
|
||||
return !this.is_declared(compressor);
|
||||
});
|
||||
def(AST_Try, function(compressor) {
|
||||
return this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)
|
||||
return (this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor))
|
||||
|| this.bfinally && this.bfinally.may_throw(compressor);
|
||||
});
|
||||
def(AST_Unary, function(compressor) {
|
||||
@@ -3878,7 +3882,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return scan_ref_scoped(node, descend);
|
||||
return scan_ref_scoped(node, descend, true);
|
||||
});
|
||||
self.walk(tw);
|
||||
// pass 2: for every used symbol we need to walk its
|
||||
@@ -3912,6 +3916,11 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Assign) {
|
||||
if (!in_use || node.left === sym && def.id in fixed_ids && fixed_ids[def.id] !== node) {
|
||||
value = get_rhs(node);
|
||||
if (node.write_only === true) {
|
||||
value = value.drop_side_effect_free(compressor) || make_node(AST_Number, node, {
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (!in_use) {
|
||||
value = make_node(AST_Number, node, {
|
||||
@@ -4181,7 +4190,7 @@ merge(Compressor.prototype, {
|
||||
return rhs.right.has_side_effects(compressor) ? rhs : rhs.right;
|
||||
}
|
||||
|
||||
function scan_ref_scoped(node, descend) {
|
||||
function scan_ref_scoped(node, descend, init) {
|
||||
var node_def, props = [], sym = assign_as_unused(node, props);
|
||||
if (sym && self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||
props.forEach(function(prop) {
|
||||
@@ -4190,7 +4199,11 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Assign) {
|
||||
if (node.write_only === "p" && node.right.may_throw_on_access(compressor)) return;
|
||||
var right = get_rhs(node);
|
||||
right.walk(tw);
|
||||
if (init && node.write_only === true && node_def.scope === self && !right.has_side_effects(compressor)) {
|
||||
initializations.add(node_def.id, right);
|
||||
} else {
|
||||
right.walk(tw);
|
||||
}
|
||||
if (node.left === sym) {
|
||||
if (!node_def.chained && sym.fixed_value(true) === right) {
|
||||
fixed_ids[node_def.id] = node;
|
||||
@@ -4349,6 +4362,96 @@ merge(Compressor.prototype, {
|
||||
self.body = dirs.concat(hoisted, self.body);
|
||||
});
|
||||
|
||||
function scan_local_returns(fn, transform) {
|
||||
fn.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Return) {
|
||||
transform(node);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope && node !== fn) return true;
|
||||
}));
|
||||
}
|
||||
|
||||
function map_bool_returns(fn) {
|
||||
var map = Object.create(null);
|
||||
scan_local_returns(fn, function(node) {
|
||||
var value = node.value;
|
||||
if (value) value = value.tail_node();
|
||||
if (value instanceof AST_SymbolRef) {
|
||||
var id = value.definition().id;
|
||||
map[id] = (map[id] || 0) + 1;
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function all_bool(def, bool_returns, compressor) {
|
||||
return def.bool_fn + (bool_returns[def.id] || 0) === def.references.length
|
||||
&& !compressor.exposed(def);
|
||||
}
|
||||
|
||||
function process_boolean_returns(fn, compressor) {
|
||||
scan_local_returns(fn, function(node) {
|
||||
node.in_bool = true;
|
||||
var value = node.value;
|
||||
if (value) {
|
||||
var ev = value.is_truthy() || value.tail_node().evaluate(compressor);
|
||||
if (!ev) {
|
||||
value = value.drop_side_effect_free(compressor);
|
||||
if (node.value !== value) node.value = value ? make_sequence(node.value, [
|
||||
value,
|
||||
make_node(AST_Number, node.value, {
|
||||
value: 0
|
||||
})
|
||||
]) : null;
|
||||
} else if (ev && !(ev instanceof AST_Node)) {
|
||||
value = value.drop_side_effect_free(compressor);
|
||||
if (node.value !== value) node.value = value ? make_sequence(node.value, [
|
||||
value,
|
||||
make_node(AST_Number, node.value, {
|
||||
value: 1
|
||||
})
|
||||
]) : make_node(AST_Number, node.value, {
|
||||
value: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AST_Scope.DEFMETHOD("process_boolean_returns", noop);
|
||||
AST_Defun.DEFMETHOD("process_boolean_returns", function(compressor) {
|
||||
if (!compressor.option("booleans")) return;
|
||||
var bool_returns = map_bool_returns(this);
|
||||
if (!all_bool(this.name.definition(), bool_returns, compressor)) return;
|
||||
process_boolean_returns(this, compressor);
|
||||
});
|
||||
AST_Function.DEFMETHOD("process_boolean_returns", function(compressor) {
|
||||
if (!compressor.option("booleans")) return;
|
||||
var bool_returns = map_bool_returns(this);
|
||||
if (this.name && !all_bool(this.name.definition(), bool_returns, compressor)) return;
|
||||
var parent = compressor.parent();
|
||||
if (parent instanceof AST_Assign) {
|
||||
if (parent.operator != "=") return;
|
||||
var sym = parent.left;
|
||||
if (!(sym instanceof AST_SymbolRef)) return;
|
||||
if (!all_bool(sym.definition(), bool_returns, compressor)) return;
|
||||
} else if (parent instanceof AST_Call && parent.expression !== this) {
|
||||
var exp = parent.expression;
|
||||
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
||||
if (!(exp instanceof AST_Lambda)) return;
|
||||
if (exp.uses_arguments || exp.pinned()) return;
|
||||
var sym = exp.argnames[parent.args.indexOf(this)];
|
||||
if (sym && !all_bool(sym.definition(), bool_returns, compressor)) return;
|
||||
} else if (parent.TYPE == "Call") {
|
||||
compressor.pop();
|
||||
var in_bool = compressor.in_boolean_context();
|
||||
compressor.push(this);
|
||||
if (!in_bool) return;
|
||||
} else return;
|
||||
process_boolean_returns(this, compressor);
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("var_names", function() {
|
||||
var var_names = this._var_names;
|
||||
if (!var_names) {
|
||||
@@ -4561,7 +4664,12 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
|
||||
var node = this.clone();
|
||||
exp.process_expression(false, compressor);
|
||||
exp.process_expression(false, function(node) {
|
||||
var value = node.value && node.value.drop_side_effect_free(compressor, true);
|
||||
return value ? make_node(AST_SimpleStatement, node, {
|
||||
body: value
|
||||
}) : make_node(AST_EmptyStatement, node);
|
||||
});
|
||||
exp.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Return && node.value) {
|
||||
node.value = node.value.drop_side_effect_free(compressor);
|
||||
@@ -4878,7 +4986,7 @@ merge(Compressor.prototype, {
|
||||
var sym = condition.right.expression;
|
||||
if (!is_undeclared_ref(sym)) return;
|
||||
var body;
|
||||
var undef = condition.left.getValue() == "undefined";
|
||||
var undef = condition.left.value == "undefined";
|
||||
switch (condition.operator) {
|
||||
case "==":
|
||||
body = undef ? alternative : consequent;
|
||||
@@ -5006,13 +5114,17 @@ merge(Compressor.prototype, {
|
||||
if (self.body instanceof AST_Exit
|
||||
&& self.alternative instanceof AST_Exit
|
||||
&& self.body.TYPE == self.alternative.TYPE) {
|
||||
return make_node(self.body.CTOR, self, {
|
||||
var exit = make_node(self.body.CTOR, self, {
|
||||
value: make_node(AST_Conditional, self, {
|
||||
condition : self.condition,
|
||||
consequent : self.body.value || make_node(AST_Undefined, self.body),
|
||||
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative)
|
||||
}).transform(compressor)
|
||||
}).optimize(compressor);
|
||||
consequent : self.body.value || make_node(AST_Undefined, self.body).transform(compressor),
|
||||
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).transform(compressor)
|
||||
})
|
||||
});
|
||||
if (exit instanceof AST_Return) {
|
||||
exit.in_bool = self.body.in_bool || self.alternative.in_bool;
|
||||
}
|
||||
return exit;
|
||||
}
|
||||
if (self.body instanceof AST_If
|
||||
&& !self.body.alternative
|
||||
@@ -5314,7 +5426,7 @@ merge(Compressor.prototype, {
|
||||
if (self.args.length == 1) {
|
||||
var first = self.args[0];
|
||||
if (first instanceof AST_Number) try {
|
||||
var length = first.getValue();
|
||||
var length = first.value;
|
||||
if (length > 6) break;
|
||||
var elements = Array(length);
|
||||
for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
|
||||
@@ -5927,7 +6039,7 @@ merge(Compressor.prototype, {
|
||||
} else if (compressor.in_boolean_context()) switch (self.operator) {
|
||||
case "!":
|
||||
if (e instanceof AST_UnaryPrefix && e.operator == "!") {
|
||||
// !!foo ==> foo, if we're in boolean context
|
||||
// !!foo => foo, if we're in boolean context
|
||||
return e.expression;
|
||||
}
|
||||
if (e instanceof AST_Binary) {
|
||||
@@ -5999,6 +6111,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||
var minus_zero_op = makePredicate("- * / %");
|
||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||
function is_object(node) {
|
||||
return node instanceof AST_Array
|
||||
@@ -6072,7 +6185,7 @@ merge(Compressor.prototype, {
|
||||
// "undefined" == typeof x => undefined === x
|
||||
else if (compressor.option("typeofs")
|
||||
&& self.left instanceof AST_String
|
||||
&& self.left.getValue() == "undefined"
|
||||
&& self.left.value == "undefined"
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
&& self.right.operator == "typeof") {
|
||||
var expr = self.right.expression;
|
||||
@@ -6144,7 +6257,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
case "==":
|
||||
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||
if (self.left instanceof AST_String && self.left.value == "" && self.right.is_string(compressor)) {
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator: "!",
|
||||
expression: self.right
|
||||
@@ -6152,7 +6265,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
case "!=":
|
||||
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||
if (self.left instanceof AST_String && self.left.value == "" && self.right.is_string(compressor)) {
|
||||
return self.right.optimize(compressor);
|
||||
}
|
||||
break;
|
||||
@@ -6173,19 +6286,19 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (self.operator == "+") {
|
||||
if (self.right instanceof AST_String
|
||||
&& self.right.getValue() == ""
|
||||
&& self.right.value == ""
|
||||
&& self.left.is_string(compressor)) {
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
if (self.left instanceof AST_String
|
||||
&& self.left.getValue() == ""
|
||||
&& self.left.value == ""
|
||||
&& self.right.is_string(compressor)) {
|
||||
return self.right.optimize(compressor);
|
||||
}
|
||||
if (self.left instanceof AST_Binary
|
||||
&& self.left.operator == "+"
|
||||
&& self.left.left instanceof AST_String
|
||||
&& self.left.left.getValue() == ""
|
||||
&& self.left.left.value == ""
|
||||
&& self.right.is_string(compressor)) {
|
||||
self.left = self.left.right;
|
||||
return self.optimize(compressor);
|
||||
@@ -6218,9 +6331,9 @@ merge(Compressor.prototype, {
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
}
|
||||
// x || false && y ---> x ? y : false
|
||||
// (x || false) && y => x ? y : false
|
||||
if (self.left.operator == "||") {
|
||||
var lr = self.left.right.evaluate(compressor);
|
||||
var lr = self.left.right.tail_node().evaluate(compressor);
|
||||
if (!lr) return make_node(AST_Conditional, self, {
|
||||
condition: self.left.left,
|
||||
consequent: self.right,
|
||||
@@ -6252,8 +6365,9 @@ merge(Compressor.prototype, {
|
||||
]).optimize(compressor);
|
||||
} else self.truthy = true;
|
||||
}
|
||||
// x && true || y => x ? true : y
|
||||
if (self.left.operator == "&&") {
|
||||
var lr = self.left.right.evaluate(compressor);
|
||||
var lr = self.left.right.is_truthy() || self.left.right.tail_node().evaluate(compressor);
|
||||
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
|
||||
condition: self.left.left,
|
||||
consequent: self.left.right,
|
||||
@@ -6271,7 +6385,7 @@ merge(Compressor.prototype, {
|
||||
self = make_node(AST_Binary, self, {
|
||||
operator: "+",
|
||||
left: make_node(AST_String, self.left, {
|
||||
value: "" + self.left.getValue() + self.right.left.getValue(),
|
||||
value: "" + self.left.value + self.right.left.value,
|
||||
start: self.left.start,
|
||||
end: self.right.left.end
|
||||
}),
|
||||
@@ -6288,7 +6402,7 @@ merge(Compressor.prototype, {
|
||||
operator: "+",
|
||||
left: self.left.left,
|
||||
right: make_node(AST_String, self.right, {
|
||||
value: "" + self.left.right.getValue() + self.right.getValue(),
|
||||
value: "" + self.left.right.value + self.right.value,
|
||||
start: self.left.right.start,
|
||||
end: self.right.end
|
||||
})
|
||||
@@ -6309,7 +6423,7 @@ merge(Compressor.prototype, {
|
||||
operator: "+",
|
||||
left: self.left.left,
|
||||
right: make_node(AST_String, self.left.right, {
|
||||
value: "" + self.left.right.getValue() + self.right.left.getValue(),
|
||||
value: "" + self.left.right.value + self.right.left.value,
|
||||
start: self.left.right.start,
|
||||
end: self.right.left.end
|
||||
})
|
||||
@@ -6392,8 +6506,8 @@ merge(Compressor.prototype, {
|
||||
// a + +b => +b + a
|
||||
if (self.operator != "-"
|
||||
&& self.operator != "/"
|
||||
&& self.left.is_number(compressor)
|
||||
&& self.right.is_number(compressor)
|
||||
&& (self.left.is_boolean(compressor) || self.left.is_number(compressor))
|
||||
&& (self.right.is_boolean(compressor) || self.right.is_number(compressor))
|
||||
&& reversible()
|
||||
&& !(self.left instanceof AST_Binary
|
||||
&& self.left.operator != self.operator
|
||||
@@ -6418,7 +6532,9 @@ merge(Compressor.prototype, {
|
||||
&& self.right.is_number(compressor)
|
||||
&& (self.operator != "+"
|
||||
|| self.right.left.is_boolean(compressor)
|
||||
|| self.right.left.is_number(compressor))) {
|
||||
|| self.right.left.is_number(compressor))
|
||||
&& (self.right.left.is_constant_expression()
|
||||
|| !self.right.right.has_side_effects(compressor))) {
|
||||
self = make_node(AST_Binary, self, {
|
||||
operator: align(self.operator, self.right.operator),
|
||||
left: make_node(AST_Binary, self.left, {
|
||||
@@ -6456,6 +6572,57 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
|
||||
// 0 + n => n
|
||||
case "+":
|
||||
if (self.left.value == 0) {
|
||||
if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
||||
operator: "+",
|
||||
expression: self.right
|
||||
}).optimize(compressor);
|
||||
if (self.right.is_number(compressor) && !may_be_minus_zero(self.right)) return self.right;
|
||||
}
|
||||
break;
|
||||
// 1 * n => n
|
||||
case "*":
|
||||
if (self.left.value == 1) {
|
||||
return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
|
||||
operator: "+",
|
||||
expression: self.right
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
|
||||
// n + 0 => n
|
||||
case "+":
|
||||
if (self.right.value == 0) {
|
||||
if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
|
||||
operator: "+",
|
||||
expression: self.left
|
||||
}).optimize(compressor);
|
||||
if (self.left.is_number(compressor) && !may_be_minus_zero(self.left)) return self.left;
|
||||
}
|
||||
break;
|
||||
// n - 0 => n
|
||||
case "-":
|
||||
if (self.right.value == 0) {
|
||||
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
||||
operator: "+",
|
||||
expression: self.left
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
// n / 1 => n
|
||||
case "/":
|
||||
if (self.right.value == 1) {
|
||||
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
|
||||
operator: "+",
|
||||
expression: self.left
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (compressor.option("typeofs")) switch (self.operator) {
|
||||
case "&&":
|
||||
@@ -6471,7 +6638,7 @@ merge(Compressor.prototype, {
|
||||
&& indexRight
|
||||
&& (self.operator == "==" || self.operator == "!=")
|
||||
&& self.left instanceof AST_Number
|
||||
&& self.left.getValue() == 0) {
|
||||
&& self.left.value == 0) {
|
||||
return (self.operator == "==" ? make_node(AST_UnaryPrefix, self, {
|
||||
operator: "!",
|
||||
expression: self.right
|
||||
@@ -6500,10 +6667,10 @@ merge(Compressor.prototype, {
|
||||
return node.optimize(compressor);
|
||||
}
|
||||
}
|
||||
// x && (y && z) ==> x && y && z
|
||||
// x || (y || z) ==> x || y || z
|
||||
// x + ("y" + z) ==> x + "y" + z
|
||||
// "x" + (y + "z")==> "x" + y + "z"
|
||||
// x && (y && z) => x && y && z
|
||||
// x || (y || z) => x || y || z
|
||||
// x + ("y" + z) => x + "y" + z
|
||||
// "x" + (y + "z") => "x" + y + "z"
|
||||
if (self.right instanceof AST_Binary
|
||||
&& self.right.operator == self.operator
|
||||
&& (lazy_op[self.operator]
|
||||
@@ -6574,21 +6741,35 @@ merge(Compressor.prototype, {
|
||||
switch (self.operator) {
|
||||
case "<=":
|
||||
// 0 <= array.indexOf(string) => !!~array.indexOf(string)
|
||||
return indexRight && self.left instanceof AST_Number && self.left.getValue() == 0;
|
||||
return indexRight && self.left instanceof AST_Number && self.left.value == 0;
|
||||
case "<":
|
||||
// array.indexOf(string) < 0 => !~array.indexOf(string)
|
||||
if (indexLeft && self.right instanceof AST_Number && self.right.getValue() == 0) return true;
|
||||
if (indexLeft && self.right instanceof AST_Number && self.right.value == 0) return true;
|
||||
// -1 < array.indexOf(string) => !!~array.indexOf(string)
|
||||
case "==":
|
||||
case "!=":
|
||||
// -1 == array.indexOf(string) => !~array.indexOf(string)
|
||||
// -1 != array.indexOf(string) => !!~array.indexOf(string)
|
||||
if (!indexRight) return false;
|
||||
return self.left instanceof AST_Number && self.left.getValue() == -1
|
||||
return self.left instanceof AST_Number && self.left.value == -1
|
||||
|| self.left instanceof AST_UnaryPrefix && self.left.operator == "-"
|
||||
&& self.left.expression instanceof AST_Number && self.left.expression.getValue() == 1;
|
||||
&& self.left.expression instanceof AST_Number && self.left.expression.value == 1;
|
||||
}
|
||||
}
|
||||
|
||||
function may_be_minus_zero(node) {
|
||||
var ev = node.evaluate(compressor);
|
||||
if (ev instanceof AST_Node) {
|
||||
var op = ev.operator;
|
||||
if (!op) return true;
|
||||
if (ev instanceof AST_Assign) {
|
||||
if (op == "=") return may_be_minus_zero(ev.right);
|
||||
op = op.slice(0, -1);
|
||||
}
|
||||
if (minus_zero_op[op]) return true;
|
||||
if (ev instanceof AST_UnaryPrefix && op == "+") return true;
|
||||
} else if (ev == 0 && 1 / ev < 0) return true;
|
||||
}
|
||||
});
|
||||
|
||||
function recursive_ref(compressor, def) {
|
||||
@@ -6621,24 +6802,28 @@ merge(Compressor.prototype, {
|
||||
var def = self.definition();
|
||||
var fixed = self.fixed_value();
|
||||
var single_use = def.single_use && !(parent instanceof AST_Call && parent.is_expr_pure(compressor));
|
||||
if (single_use && fixed instanceof AST_Lambda) {
|
||||
if (def.scope !== self.scope
|
||||
&& (!compressor.option("reduce_funcs") || def.escaped.depth == 1 || fixed.inlined)) {
|
||||
single_use = false;
|
||||
} else if (recursive_ref(compressor, def)) {
|
||||
single_use = false;
|
||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
var scope = self.scope;
|
||||
do if (scope instanceof AST_Defun || scope instanceof AST_Function) {
|
||||
scope.inlined = true;
|
||||
} while (scope = scope.parent_scope);
|
||||
if (single_use) {
|
||||
if (fixed instanceof AST_Lambda) {
|
||||
if (def.scope !== self.scope
|
||||
&& (!compressor.option("reduce_funcs") || def.escaped.depth == 1 || fixed.inlined)) {
|
||||
single_use = false;
|
||||
} else if (recursive_ref(compressor, def)) {
|
||||
single_use = false;
|
||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
var scope = self.scope;
|
||||
do if (scope instanceof AST_Defun || scope instanceof AST_Function) {
|
||||
scope.inlined = true;
|
||||
} while (scope = scope.parent_scope);
|
||||
}
|
||||
}
|
||||
if (single_use) fixed.parent_scope = self.scope;
|
||||
} else if (!fixed || !fixed.is_constant_expression()) {
|
||||
single_use = false;
|
||||
}
|
||||
if (single_use) fixed.parent_scope = self.scope;
|
||||
}
|
||||
if (single_use && fixed) {
|
||||
if (single_use) {
|
||||
def.single_use = false;
|
||||
fixed._squeezed = true;
|
||||
fixed.single_use = true;
|
||||
@@ -6891,7 +7076,7 @@ merge(Compressor.prototype, {
|
||||
if (self.right.left instanceof AST_SymbolRef
|
||||
&& self.right.left.name == self.left.name
|
||||
&& ASSIGN_OPS[self.right.operator]) {
|
||||
// x = x - 2 ---> x -= 2
|
||||
// x = x - 2 => x -= 2
|
||||
self.operator = self.right.operator + "=";
|
||||
self.right = self.right.right;
|
||||
}
|
||||
@@ -6899,7 +7084,7 @@ merge(Compressor.prototype, {
|
||||
&& self.right.right.name == self.left.name
|
||||
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator]
|
||||
&& !self.right.left.has_side_effects(compressor)) {
|
||||
// x = 2 & x ---> x &= 2
|
||||
// x = 2 & x => x &= 2
|
||||
self.operator = self.right.operator + "=";
|
||||
self.right = self.right.left;
|
||||
}
|
||||
@@ -6907,7 +7092,7 @@ merge(Compressor.prototype, {
|
||||
if ((self.operator == "-=" || self.operator == "+="
|
||||
&& (self.left.is_boolean(compressor) || self.left.is_number(compressor)))
|
||||
&& self.right instanceof AST_Number
|
||||
&& self.right.getValue() === 1) {
|
||||
&& self.right.value == 1) {
|
||||
var op = self.operator.slice(0, -1);
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator: op + op,
|
||||
@@ -6968,7 +7153,7 @@ merge(Compressor.prototype, {
|
||||
var condition = self.condition;
|
||||
var consequent = self.consequent;
|
||||
var alternative = self.alternative;
|
||||
// x?x:y --> x||y
|
||||
// x ? x : y => x || y
|
||||
if (condition instanceof AST_SymbolRef
|
||||
&& consequent instanceof AST_SymbolRef
|
||||
&& condition.definition() === consequent.definition()) {
|
||||
@@ -7005,7 +7190,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
// x ? y : y --> x, y
|
||||
// x ? y : y => x, y
|
||||
if (consequent.equivalent_to(alternative)) return make_sequence(self, [
|
||||
condition,
|
||||
consequent
|
||||
@@ -7014,7 +7199,7 @@ merge(Compressor.prototype, {
|
||||
&& alternative.TYPE === consequent.TYPE
|
||||
&& consequent.args.length == alternative.args.length) {
|
||||
var arg_index = arg_diff();
|
||||
// x ? y(a) : z(a) --> (x ? y : z)(a)
|
||||
// x ? y(a) : z(a) => (x ? y : z)(a)
|
||||
if (arg_index == -1
|
||||
&& !(consequent.expression instanceof AST_PropAccess)
|
||||
&& !(alternative.expression instanceof AST_PropAccess)) {
|
||||
@@ -7026,7 +7211,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
return node;
|
||||
}
|
||||
// x ? y(a) : y(b) --> y(x ? a : b)
|
||||
// x ? y(a) : y(b) => y(x ? a : b)
|
||||
if (arg_index >= 0
|
||||
&& consequent.expression.equivalent_to(alternative.expression)
|
||||
&& !condition.has_side_effects(compressor)
|
||||
@@ -7040,7 +7225,7 @@ merge(Compressor.prototype, {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
// x ? (y ? a : b) : b --> x && y ? a : b
|
||||
// x ? (y ? a : b) : b => x && y ? a : b
|
||||
if (consequent instanceof AST_Conditional
|
||||
&& consequent.alternative.equivalent_to(alternative)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
@@ -7053,7 +7238,7 @@ merge(Compressor.prototype, {
|
||||
alternative: alternative
|
||||
});
|
||||
}
|
||||
// x ? a : (y ? a : b)--> x || y ? a : b
|
||||
// x ? a : (y ? a : b) => x || y ? a : b
|
||||
if (alternative instanceof AST_Conditional
|
||||
&& consequent.equivalent_to(alternative.consequent)) {
|
||||
return make_node(AST_Conditional, self, {
|
||||
@@ -7066,7 +7251,7 @@ merge(Compressor.prototype, {
|
||||
alternative: alternative.alternative
|
||||
});
|
||||
}
|
||||
// x ? (y, w) : (z, w) --> x ? y : z, w
|
||||
// x ? (y, w) : (z, w) => x ? y : z, w
|
||||
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
||||
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
|
||||
return make_sequence(self, [
|
||||
@@ -7078,7 +7263,7 @@ merge(Compressor.prototype, {
|
||||
consequent.tail_node()
|
||||
]).optimize(compressor);
|
||||
}
|
||||
// x ? y || z : z --> x && y || z
|
||||
// x ? y || z : z => x && y || z
|
||||
if (consequent instanceof AST_Binary
|
||||
&& consequent.operator == "||"
|
||||
&& consequent.right.equivalent_to(alternative)) {
|
||||
@@ -7095,10 +7280,10 @@ merge(Compressor.prototype, {
|
||||
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
||||
if (is_true(consequent)) {
|
||||
if (is_false(alternative)) {
|
||||
// c ? true : false ---> !!c
|
||||
// c ? true : false => !!c
|
||||
return booleanize(condition);
|
||||
}
|
||||
// c ? true : x ---> !!c || x
|
||||
// c ? true : x => !!c || x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: booleanize(condition),
|
||||
@@ -7107,10 +7292,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (is_false(consequent)) {
|
||||
if (is_true(alternative)) {
|
||||
// c ? false : true ---> !c
|
||||
// c ? false : true => !c
|
||||
return booleanize(condition.negate(compressor));
|
||||
}
|
||||
// c ? false : x ---> !c && x
|
||||
// c ? false : x => !c && x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: booleanize(condition.negate(compressor)),
|
||||
@@ -7118,7 +7303,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
if (is_true(alternative)) {
|
||||
// c ? x : true ---> !c || x
|
||||
// c ? x : true => !c || x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: booleanize(condition.negate(compressor)),
|
||||
@@ -7126,7 +7311,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
if (is_false(alternative)) {
|
||||
// c ? x : false ---> !!c && x
|
||||
// c ? x : false => !!c && x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: booleanize(condition),
|
||||
@@ -7150,22 +7335,25 @@ merge(Compressor.prototype, {
|
||||
return node instanceof AST_True
|
||||
|| in_bool
|
||||
&& node instanceof AST_Constant
|
||||
&& node.getValue()
|
||||
&& node.value
|
||||
|| (node instanceof AST_UnaryPrefix
|
||||
&& node.operator == "!"
|
||||
&& node.expression instanceof AST_Constant
|
||||
&& !node.expression.getValue());
|
||||
&& !node.expression.value);
|
||||
}
|
||||
// AST_False or !1
|
||||
// AST_False or !1 or void 0
|
||||
function is_false(node) {
|
||||
return node instanceof AST_False
|
||||
|| in_bool
|
||||
&& node instanceof AST_Constant
|
||||
&& !node.getValue()
|
||||
&& (node instanceof AST_Constant
|
||||
&& !node.value
|
||||
|| node instanceof AST_UnaryPrefix
|
||||
&& node.operator == "void"
|
||||
&& !node.expression.has_side_effects(compressor))
|
||||
|| (node instanceof AST_UnaryPrefix
|
||||
&& node.operator == "!"
|
||||
&& node.expression instanceof AST_Constant
|
||||
&& node.expression.getValue());
|
||||
&& node.expression.value);
|
||||
}
|
||||
|
||||
function arg_diff() {
|
||||
@@ -7273,7 +7461,7 @@ merge(Compressor.prototype, {
|
||||
&& is_arguments(def = expr.definition())
|
||||
&& prop instanceof AST_Number
|
||||
&& (fn = expr.scope) === find_lambda()) {
|
||||
var index = prop.getValue();
|
||||
var index = prop.value;
|
||||
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") {
|
||||
if (!def.deleted) def.deleted = [];
|
||||
def.deleted[index] = true;
|
||||
@@ -7319,7 +7507,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (compressor.option("properties") && compressor.option("side_effects")
|
||||
&& prop instanceof AST_Number && expr instanceof AST_Array) {
|
||||
var index = prop.getValue();
|
||||
var index = prop.value;
|
||||
var elements = expr.elements;
|
||||
var retValue = elements[index];
|
||||
if (safe_to_flatten(retValue, compressor)) {
|
||||
|
||||
@@ -119,15 +119,20 @@ function OutputStream(options) {
|
||||
});
|
||||
} : function(str) {
|
||||
var s = "";
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|
||||
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
|
||||
s += "\\u" + str.charCodeAt(i).toString(16);
|
||||
} else {
|
||||
s += str[i];
|
||||
for (var i = 0, j = 0; i < str.length; i++) {
|
||||
var code = str.charCodeAt(i);
|
||||
if (is_surrogate_pair_head(code)) {
|
||||
if (is_surrogate_pair_tail(str.charCodeAt(i + 1))) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
} else if (!is_surrogate_pair_tail(code)) {
|
||||
continue;
|
||||
}
|
||||
s += str.slice(j, i) + "\\u" + code.toString(16);
|
||||
j = i + 1;
|
||||
}
|
||||
return s;
|
||||
return j == 0 ? str : s + str.slice(j);
|
||||
};
|
||||
|
||||
function make_string(str, quote) {
|
||||
@@ -777,7 +782,7 @@ function OutputStream(options) {
|
||||
PARENS(AST_Number, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
var value = this.getValue();
|
||||
var value = this.value;
|
||||
if (value < 0 || /^0/.test(make_num(value))) {
|
||||
return true;
|
||||
}
|
||||
@@ -1207,7 +1212,7 @@ function OutputStream(options) {
|
||||
output.print_string(prop);
|
||||
output.print("]");
|
||||
} else {
|
||||
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||
if (expr instanceof AST_Number && expr.value >= 0) {
|
||||
if (!/[xa-f.)]/i.test(output.last())) {
|
||||
output.print(".");
|
||||
}
|
||||
@@ -1331,21 +1336,21 @@ function OutputStream(options) {
|
||||
output.print("this");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(self, output) {
|
||||
output.print(self.getValue());
|
||||
output.print(self.value);
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output) {
|
||||
output.print_string(self.getValue(), self.quote);
|
||||
output.print_string(self.value, self.quote);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output) {
|
||||
if (use_asm && self.start && self.start.raw != null) {
|
||||
output.print(self.start.raw);
|
||||
} else {
|
||||
output.print(make_num(self.getValue()));
|
||||
output.print(make_num(self.value));
|
||||
}
|
||||
});
|
||||
|
||||
DEFPRINT(AST_RegExp, function(self, output) {
|
||||
var regexp = self.getValue();
|
||||
var regexp = self.value;
|
||||
var str = regexp.toString();
|
||||
if (regexp.raw_source) {
|
||||
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||
|
||||
@@ -133,14 +133,10 @@ function is_letter(code) {
|
||||
}
|
||||
|
||||
function is_surrogate_pair_head(code) {
|
||||
if (typeof code == "string")
|
||||
code = code.charCodeAt(0);
|
||||
return code >= 0xd800 && code <= 0xdbff;
|
||||
}
|
||||
|
||||
function is_surrogate_pair_tail(code) {
|
||||
if (typeof code == "string")
|
||||
code = code.charCodeAt(0);
|
||||
return code >= 0xdc00 && code <= 0xdfff;
|
||||
}
|
||||
|
||||
|
||||
@@ -428,6 +428,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
if (options.cache && node instanceof AST_Toplevel) {
|
||||
node.globals.each(mangle);
|
||||
}
|
||||
if (node instanceof AST_Defun && tw.has_directive("use asm")) {
|
||||
var sym = new AST_SymbolRef(node.name);
|
||||
sym.scope = node;
|
||||
sym.reference(options);
|
||||
}
|
||||
node.variables.each(function(def) {
|
||||
if (!defer_redef(def)) mangle(def);
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.7.3",
|
||||
"version": "3.7.5",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -166,3 +166,69 @@ asm_nested_functions: {
|
||||
}
|
||||
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
|
||||
}
|
||||
|
||||
issue_3636_1: {
|
||||
mangle = {}
|
||||
input: {
|
||||
function n(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
function add(x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
return x + y | 0;
|
||||
}
|
||||
return {
|
||||
add: add
|
||||
};
|
||||
}
|
||||
console.log(new n().add("foo", 42));
|
||||
}
|
||||
expect: {
|
||||
function n(o, e, u) {
|
||||
"use asm";
|
||||
function d(n, o) {
|
||||
n = n | 0;
|
||||
o = o | 0;
|
||||
return n + o | 0;
|
||||
}
|
||||
return {
|
||||
add: d
|
||||
};
|
||||
}
|
||||
console.log(new n().add("foo", 42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_3636_2: {
|
||||
mangle = {}
|
||||
input: {
|
||||
var n = function(stdlib, foreign, buffer) {
|
||||
"use asm";
|
||||
function add(x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
return x + y | 0;
|
||||
}
|
||||
return {
|
||||
add: add
|
||||
};
|
||||
};
|
||||
console.log(new n().add("foo", 42));
|
||||
}
|
||||
expect: {
|
||||
var n = function(n, o, e) {
|
||||
"use asm";
|
||||
function r(n, o) {
|
||||
n = n | 0;
|
||||
o = o | 0;
|
||||
return n + o | 0;
|
||||
}
|
||||
return {
|
||||
add: r
|
||||
};
|
||||
};
|
||||
console.log(new n().add("foo", 42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -86,3 +86,48 @@ issue_3465_3: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2737_2: {
|
||||
options = {
|
||||
booleans: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(bar) {
|
||||
for (;bar();) break;
|
||||
})(function qux() {
|
||||
return console.log("PASS"), qux;
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(bar) {
|
||||
for (;bar();) break;
|
||||
})(function() {
|
||||
return console.log("PASS"), 1;
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3658: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
console || f();
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
console || f();
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -5863,8 +5863,8 @@ issue_2974: {
|
||||
var c = 0;
|
||||
(function(b) {
|
||||
var a = 2;
|
||||
for (; b.null = -4, c++, b.null && --a > 0;);
|
||||
})(!0),
|
||||
for (;c++, (!0).null && --a > 0;);
|
||||
})(),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
@@ -7422,3 +7422,72 @@ issue_3641: {
|
||||
}
|
||||
expect_stdout: "foo undefined"
|
||||
}
|
||||
|
||||
issue_3651: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a, b = "PASS";
|
||||
try {
|
||||
a = function() {
|
||||
try {
|
||||
var c = 1;
|
||||
while (0 < --c);
|
||||
} catch (e) {} finally {
|
||||
throw 42;
|
||||
}
|
||||
}();
|
||||
b = "FAIL";
|
||||
a.p;
|
||||
} catch (e) {
|
||||
console.log(b);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a, b = "PASS";
|
||||
try {
|
||||
a = function() {
|
||||
try {
|
||||
var c = 1;
|
||||
while (0 < --c);
|
||||
} catch (e) {} finally {
|
||||
throw 42;
|
||||
}
|
||||
}();
|
||||
b = "FAIL";
|
||||
a.p;
|
||||
} catch (e) {
|
||||
console.log(b);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3671: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
try {
|
||||
a++;
|
||||
A += 0;
|
||||
a = 1 + a;
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
try {
|
||||
a++;
|
||||
A += 0;
|
||||
a = 1 + a;
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -1578,3 +1578,34 @@ issue_3576: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3668: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
try {
|
||||
var undefined = typeof f;
|
||||
if (!f) return undefined;
|
||||
return;
|
||||
} catch (e) {
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
try {
|
||||
var undefined = typeof f;
|
||||
return f ? void 0 : undefined;
|
||||
} catch (e) {
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -141,207 +141,6 @@ try_catch_finally: {
|
||||
]
|
||||
}
|
||||
|
||||
accessor: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
get a() {},
|
||||
set a(v){
|
||||
this.b = 2;
|
||||
},
|
||||
b: 1
|
||||
});
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2233_1: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Array.isArray;
|
||||
Boolean;
|
||||
console.log;
|
||||
Date;
|
||||
decodeURI;
|
||||
decodeURIComponent;
|
||||
encodeURI;
|
||||
encodeURIComponent;
|
||||
Error.name;
|
||||
escape;
|
||||
eval;
|
||||
EvalError;
|
||||
Function.length;
|
||||
isFinite;
|
||||
isNaN;
|
||||
JSON;
|
||||
Math.random;
|
||||
Number.isNaN;
|
||||
parseFloat;
|
||||
parseInt;
|
||||
RegExp;
|
||||
Object.defineProperty;
|
||||
String.fromCharCode;
|
||||
RangeError;
|
||||
ReferenceError;
|
||||
SyntaxError;
|
||||
TypeError;
|
||||
unescape;
|
||||
URIError;
|
||||
}
|
||||
expect: {}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
global_timeout_and_interval_symbols: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
// These global symbols do not exist in the test sandbox
|
||||
// and must be tested separately.
|
||||
clearInterval;
|
||||
clearTimeout;
|
||||
setInterval;
|
||||
setTimeout;
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2233_2: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var RegExp;
|
||||
Array.isArray;
|
||||
RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Math.sin;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2233_3: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var RegExp;
|
||||
Array.isArray;
|
||||
RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Math.sin;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
UndeclaredGlobal;
|
||||
}
|
||||
}
|
||||
|
||||
global_fns: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Boolean(1, 2);
|
||||
decodeURI(1, 2);
|
||||
decodeURIComponent(1, 2);
|
||||
Date(1, 2);
|
||||
encodeURI(1, 2);
|
||||
encodeURIComponent(1, 2);
|
||||
Error(1, 2);
|
||||
escape(1, 2);
|
||||
EvalError(1, 2);
|
||||
isFinite(1, 2);
|
||||
isNaN(1, 2);
|
||||
Number(1, 2);
|
||||
Object(1, 2);
|
||||
parseFloat(1, 2);
|
||||
parseInt(1, 2);
|
||||
RangeError(1, 2);
|
||||
ReferenceError(1, 2);
|
||||
String(1, 2);
|
||||
SyntaxError(1, 2);
|
||||
TypeError(1, 2);
|
||||
unescape(1, 2);
|
||||
URIError(1, 2);
|
||||
try {
|
||||
Function(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
RegExp(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
Array(NaN);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
Function(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
RegExp(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
Array(NaN);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"SyntaxError",
|
||||
"SyntaxError",
|
||||
"RangeError",
|
||||
]
|
||||
}
|
||||
|
||||
collapse_vars_assignment: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -863,23 +662,6 @@ issue_2749: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
unsafe_builtin: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
(!w).constructor(x);
|
||||
Math.abs(y);
|
||||
[ 1, 2, z ].valueOf();
|
||||
}
|
||||
expect: {
|
||||
w, x;
|
||||
y;
|
||||
z;
|
||||
}
|
||||
}
|
||||
|
||||
issue_2860_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
@@ -941,24 +723,6 @@ issue_2929: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
unsafe_string_replace: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
"foo".replace("f", function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
"foo".replace("f", function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3402: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
|
||||
@@ -699,18 +699,6 @@ iife: {
|
||||
}
|
||||
}
|
||||
|
||||
drop_value: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(1, [2, foo()], 3, {a:1, b:bar()});
|
||||
}
|
||||
expect: {
|
||||
foo(), bar();
|
||||
}
|
||||
}
|
||||
|
||||
issue_1539: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -2266,3 +2254,124 @@ issue_3598: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
self_assign: {
|
||||
options = {
|
||||
passes: 2,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function d(a) {
|
||||
a = a;
|
||||
}
|
||||
function e(a, b) {
|
||||
a = b;
|
||||
b = a;
|
||||
}
|
||||
function f(a, b, c) {
|
||||
a = b;
|
||||
b = c;
|
||||
c = a;
|
||||
}
|
||||
function g(a, b, c) {
|
||||
a = a * b + c;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function d(a) {}
|
||||
function e(a, b) {}
|
||||
function f(a, b, c) {}
|
||||
function g(a, b, c) {}
|
||||
}
|
||||
}
|
||||
|
||||
function_argument_reference: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = 42;
|
||||
function f(a) {
|
||||
b <<= a;
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = 42;
|
||||
function f(a) {
|
||||
b <<= a;
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "1 42"
|
||||
}
|
||||
|
||||
function_parameter_ie8: {
|
||||
options = {
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
console.log("PASS");
|
||||
}
|
||||
f(a = 1 + a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f() {
|
||||
console.log("PASS");
|
||||
})(0);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3664: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var a, b = (a = (a = [ b && console.log("FAIL") ]).p = 0, 0);
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var b = ([ b && console.log("FAIL") ].p = 0, 0);
|
||||
return "PASS";
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3673: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
(a = [ a ]).p = 42;
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
(a = [ a ]).p = 42;
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -266,12 +266,7 @@ issue_2084: {
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
!function() {
|
||||
var c;
|
||||
c = 1 + (c = -1),
|
||||
c = 1 + (c = 0),
|
||||
0 !== 23..toString() && (c = 1 + c);
|
||||
}(),
|
||||
23..toString(),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
@@ -1911,14 +1906,14 @@ issue_2737_2: {
|
||||
}
|
||||
input: {
|
||||
(function(bar) {
|
||||
for (;bar(); ) break;
|
||||
for (;bar();) break;
|
||||
})(function qux() {
|
||||
return console.log("PASS"), qux;
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(bar) {
|
||||
for (;bar(); ) break;
|
||||
for (;bar();) break;
|
||||
})(function qux() {
|
||||
return console.log("PASS"), qux;
|
||||
});
|
||||
@@ -3705,3 +3700,88 @@ pr_3595_4: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3679_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var f = function() {};
|
||||
f.g = function() {
|
||||
console.log("PASS");
|
||||
};
|
||||
f.g();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3679_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
"use strict";
|
||||
var f = function() {};
|
||||
f.g = function() {
|
||||
console.log("PASS");
|
||||
};
|
||||
f.g();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
"use strict";
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3679_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
functions: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var f = function() {};
|
||||
f.p = "PASS";
|
||||
f.g = function() {
|
||||
console.log(f.p);
|
||||
};
|
||||
f.g();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
function f() {};
|
||||
f.p = "PASS";
|
||||
(f.g = function() {
|
||||
console.log(f.p);
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ issue_2519: {
|
||||
}
|
||||
expect: {
|
||||
function testFunc() {
|
||||
return 1 * ((6 + 5) / 2);
|
||||
return +((6 + 5) / 2);
|
||||
}
|
||||
console.log(testFunc());
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ while_becomes_for: {
|
||||
while (foo()) bar();
|
||||
}
|
||||
expect: {
|
||||
for (; foo(); ) bar();
|
||||
for (;foo();) bar();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ drop_if_break_1: {
|
||||
if (foo()) break;
|
||||
}
|
||||
expect: {
|
||||
for (; !foo(););
|
||||
for (;!foo(););
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ drop_if_break_2: {
|
||||
if (foo()) break;
|
||||
}
|
||||
expect: {
|
||||
for (; bar() && !foo(););
|
||||
for (;bar() && !foo(););
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ drop_if_break_4: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; bar() && (x(), y(), !foo());) z(), k();
|
||||
for (;bar() && (x(), y(), !foo());) z(), k();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ drop_if_else_break_1: {
|
||||
for (;;) if (foo()) bar(); else break;
|
||||
}
|
||||
expect: {
|
||||
for (; foo(); ) bar();
|
||||
for (;foo();) bar();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ drop_if_else_break_2: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; bar() && foo();) baz();
|
||||
for (;bar() && foo();) baz();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ drop_if_else_break_3: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; bar() && foo();) {
|
||||
for (;bar() && foo();) {
|
||||
baz();
|
||||
stuff1();
|
||||
stuff2();
|
||||
@@ -138,7 +138,7 @@ drop_if_else_break_4: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (; bar() && (x(), y(), foo());) baz(), z(), k();
|
||||
for (;bar() && (x(), y(), foo());) baz(), z(), k();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,13 +523,13 @@ issue_2740_1: {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
for (; ; ) break;
|
||||
for (a(); ; ) break;
|
||||
for (; b(); ) break;
|
||||
for (c(); d(); ) break;
|
||||
for (; ; e()) break;
|
||||
for (f(); ; g()) break;
|
||||
for (; h(); i()) break;
|
||||
for (;;) break;
|
||||
for (a();;) break;
|
||||
for (;b();) break;
|
||||
for (c(); d();) break;
|
||||
for (;;e()) break;
|
||||
for (f();; g()) break;
|
||||
for (;h(); i()) break;
|
||||
for (j(); k(); l()) break;
|
||||
}
|
||||
expect: {
|
||||
@@ -670,7 +670,7 @@ issue_3371: {
|
||||
function a() {
|
||||
console.log("PASS");
|
||||
}
|
||||
for (; a(); );
|
||||
for (;a(););
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
|
||||
@@ -91,7 +91,7 @@ evaluate_1: {
|
||||
expect: {
|
||||
console.log(
|
||||
x + 1 + 2,
|
||||
1 * x * 2,
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -173,7 +173,7 @@ evaluate_2: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
1 * x * 2,
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -979,3 +979,191 @@ unsafe_math_swap_constant: {
|
||||
}
|
||||
expect_stdout: "6 6 7 6 6 8 9 10"
|
||||
}
|
||||
|
||||
identity_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
0 + a;
|
||||
a + 0;
|
||||
0 - a;
|
||||
a - 0;
|
||||
1 * a;
|
||||
a * 1;
|
||||
1 / a;
|
||||
a / 1;
|
||||
}
|
||||
expect: {
|
||||
0 + a;
|
||||
a + 0;
|
||||
0 - a;
|
||||
+a;
|
||||
+a;
|
||||
+a;
|
||||
1 / a;
|
||||
+a;
|
||||
}
|
||||
}
|
||||
|
||||
identity_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
0 + !a;
|
||||
!a + 0;
|
||||
0 - !a;
|
||||
!a - 0;
|
||||
1 * !a;
|
||||
!a * 1;
|
||||
1 / !a;
|
||||
!a / 1;
|
||||
}
|
||||
expect: {
|
||||
+!a;
|
||||
+!a;
|
||||
0 - !a;
|
||||
+!a;
|
||||
+!a;
|
||||
+!a;
|
||||
1 / !a;
|
||||
+!a;
|
||||
}
|
||||
}
|
||||
|
||||
identity_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
0 + --a;
|
||||
--a + 0;
|
||||
0 - --a;
|
||||
--a - 0;
|
||||
1 * --a;
|
||||
--a * 1;
|
||||
1 / --a;
|
||||
--a / 1;
|
||||
}
|
||||
expect: {
|
||||
--a;
|
||||
--a;
|
||||
0 - --a;
|
||||
--a;
|
||||
--a;
|
||||
--a;
|
||||
1 / --a;
|
||||
--a;
|
||||
}
|
||||
}
|
||||
|
||||
issue_3653: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(0 - (console && 0));
|
||||
console.log(0 + (0 - (console && 0)));
|
||||
console.log(0 - (0 - (console && 0)));
|
||||
console.log(1 * (0 - (console && 0)));
|
||||
console.log(1 / (0 - (console && 0)));
|
||||
console.log((0 - (console && 0)) + 0);
|
||||
console.log((0 - (console && 0)) - 0);
|
||||
console.log((0 - (console && 0)) * 1);
|
||||
console.log((0 - (console && 0)) / 1);
|
||||
}
|
||||
expect: {
|
||||
console.log(0 - (console && 0));
|
||||
console.log(0 - (console && 0) + 0);
|
||||
console.log(0 - (0 - (console && 0)));
|
||||
console.log(0 - (console && 0));
|
||||
console.log(1 / (0 - (console && 0)));
|
||||
console.log(0 - (console && 0) + 0);
|
||||
console.log(0 - (console && 0));
|
||||
console.log(0 - (console && 0));
|
||||
console.log(0 - (console && 0));
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"Infinity",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3655: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 + (0 + 0 * -[].length));
|
||||
console.log(0 - (0 + 0 * -[].length));
|
||||
console.log(1 * (0 + 0 * -[].length));
|
||||
console.log(1 / (0 + 0 * -[].length));
|
||||
console.log((0 + 0 * -[].length) + 0);
|
||||
console.log((0 + 0 * -[].length) - 0);
|
||||
console.log((0 + 0 * -[].length) * 1);
|
||||
console.log((0 + 0 * -[].length) / 1);
|
||||
}
|
||||
expect: {
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 - (0 + 0 * -[].length));
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(1 / (0 + 0 * -[].length));
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 + 0 * -[].length);
|
||||
console.log(0 + 0 * -[].length);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"Infinity",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3676_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a = [];
|
||||
console.log(false - (a - (a[1] = 42)));
|
||||
}
|
||||
expect: {
|
||||
var a = [];
|
||||
console.log(false - (a - (a[1] = 42)));
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_3676_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
console.log(false - ((a = []) - (a[1] = 42)));
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
console.log(false - ((a = []) - (a[1] = 42)));
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
@@ -6847,3 +6847,34 @@ issue_3631_2: {
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_3666: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
var a = "FAIL";
|
||||
} finally {
|
||||
for (;!a;)
|
||||
var c = a++;
|
||||
var a = "PASS", b = c = "PASS";
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
var a = "FAIL";
|
||||
} finally {
|
||||
for (;!a;)
|
||||
a++;
|
||||
var b = a = "PASS";
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
277
test/compress/side_effects.js
Normal file
277
test/compress/side_effects.js
Normal file
@@ -0,0 +1,277 @@
|
||||
accessor: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
get a() {},
|
||||
set a(v){
|
||||
this.b = 2;
|
||||
},
|
||||
b: 1
|
||||
});
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2233_1: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Array.isArray;
|
||||
Boolean;
|
||||
console.log;
|
||||
Date;
|
||||
decodeURI;
|
||||
decodeURIComponent;
|
||||
encodeURI;
|
||||
encodeURIComponent;
|
||||
Error.name;
|
||||
escape;
|
||||
eval;
|
||||
EvalError;
|
||||
Function.length;
|
||||
isFinite;
|
||||
isNaN;
|
||||
JSON;
|
||||
Math.random;
|
||||
Number.isNaN;
|
||||
parseFloat;
|
||||
parseInt;
|
||||
RegExp;
|
||||
Object.defineProperty;
|
||||
String.fromCharCode;
|
||||
RangeError;
|
||||
ReferenceError;
|
||||
SyntaxError;
|
||||
TypeError;
|
||||
unescape;
|
||||
URIError;
|
||||
}
|
||||
expect: {}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
global_timeout_and_interval_symbols: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
// These global symbols do not exist in the test sandbox
|
||||
// and must be tested separately.
|
||||
clearInterval;
|
||||
clearTimeout;
|
||||
setInterval;
|
||||
setTimeout;
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2233_2: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var RegExp;
|
||||
Array.isArray;
|
||||
RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Math.sin;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2233_3: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var RegExp;
|
||||
Array.isArray;
|
||||
RegExp;
|
||||
UndeclaredGlobal;
|
||||
function foo() {
|
||||
var Number;
|
||||
AnotherUndeclaredGlobal;
|
||||
Math.sin;
|
||||
Number.isNaN;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
UndeclaredGlobal;
|
||||
}
|
||||
}
|
||||
|
||||
global_fns: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Boolean(1, 2);
|
||||
decodeURI(1, 2);
|
||||
decodeURIComponent(1, 2);
|
||||
Date(1, 2);
|
||||
encodeURI(1, 2);
|
||||
encodeURIComponent(1, 2);
|
||||
Error(1, 2);
|
||||
escape(1, 2);
|
||||
EvalError(1, 2);
|
||||
isFinite(1, 2);
|
||||
isNaN(1, 2);
|
||||
Number(1, 2);
|
||||
Object(1, 2);
|
||||
parseFloat(1, 2);
|
||||
parseInt(1, 2);
|
||||
RangeError(1, 2);
|
||||
ReferenceError(1, 2);
|
||||
String(1, 2);
|
||||
SyntaxError(1, 2);
|
||||
TypeError(1, 2);
|
||||
unescape(1, 2);
|
||||
URIError(1, 2);
|
||||
try {
|
||||
Function(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
RegExp(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
Array(NaN);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
Function(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
RegExp(1, 2);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
try {
|
||||
Array(NaN);
|
||||
} catch (e) {
|
||||
console.log(e.name);
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"SyntaxError",
|
||||
"SyntaxError",
|
||||
"RangeError",
|
||||
]
|
||||
}
|
||||
|
||||
unsafe_builtin_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
(!w).constructor(x);
|
||||
Math.abs(y);
|
||||
[ 1, 2, z ].valueOf();
|
||||
}
|
||||
expect: {
|
||||
w, x;
|
||||
y;
|
||||
z;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe_builtin_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
constructor.call(o, 42);
|
||||
__defineGetter__.call(o, "foo", function() {
|
||||
return o.p;
|
||||
});
|
||||
__defineSetter__.call(o, void 0, function(a) {
|
||||
o.p = a;
|
||||
});
|
||||
console.log(typeof o, o.undefined = "PASS", o.foo);
|
||||
}
|
||||
expect: {
|
||||
var o = {};
|
||||
constructor.call(o, 42);
|
||||
__defineGetter__.call(o, "foo", function() {
|
||||
return o.p;
|
||||
});
|
||||
__defineSetter__.call(o, void 0, function(a) {
|
||||
o.p = a;
|
||||
});
|
||||
console.log(typeof o, o.undefined = "PASS", o.foo);
|
||||
}
|
||||
expect_stdout: "object PASS PASS"
|
||||
}
|
||||
|
||||
unsafe_string_replace: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
"foo".replace("f", function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
"foo".replace("f", function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
drop_value: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(1, [2, foo()], 3, {a:1, b:bar()});
|
||||
}
|
||||
expect: {
|
||||
foo(), bar();
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,7 @@ if_return: {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
passes: 2,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
|
||||
@@ -16,6 +16,81 @@ unicode_parse_variables: {
|
||||
}
|
||||
}
|
||||
|
||||
unicode_escaped_identifier: {
|
||||
input: {
|
||||
var \u0061 = "\ud800\udc00";
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="\ud800\udc00";console.log(a);'
|
||||
expect_stdout: "\ud800\udc00"
|
||||
}
|
||||
|
||||
unicode_identifier_ascii_only: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var \u0061 = "testing \udbc4\udd11";
|
||||
var bar = "h\u0065llo";
|
||||
console.log(a, \u0062\u0061r);
|
||||
}
|
||||
expect_exact: 'var a="testing \\udbc4\\udd11";var bar="hello";console.log(a,bar);'
|
||||
expect_stdout: "testing \udbc4\udd11 hello"
|
||||
}
|
||||
|
||||
unicode_string_literals: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var a = "6 length unicode character: \udbc4\udd11";
|
||||
console.log(\u0061);
|
||||
}
|
||||
expect_exact: 'var a="6 length unicode character: \\udbc4\\udd11";console.log(a);'
|
||||
expect_stdout: "6 length unicode character: \udbc4\udd11"
|
||||
}
|
||||
|
||||
check_escape_style: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var a = "\x01";
|
||||
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
|
||||
var \u0100 = "\u0100";
|
||||
var \u1000 = "\u1000";
|
||||
var \u1000 = "\ud800\udc00";
|
||||
var \u3f80 = "\udbc0\udc00";
|
||||
console.log(\u0061, \ua0081, \u0100, \u1000, \u3f80);
|
||||
}
|
||||
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u1000="\\ud800\\udc00";var \\u3f80="\\udbc0\\udc00";console.log(a,\\ua0081,\\u0100,\\u1000,\\u3f80);'
|
||||
expect_stdout: "\u0001 \u0010 \u0100 \ud800\udc00 \udbc0\udc00"
|
||||
}
|
||||
|
||||
escape_non_escaped_identifier: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var µþ = "µþ";
|
||||
console.log(\u00b5þ);
|
||||
}
|
||||
expect_exact: 'var \\u00b5\\u00fe="\\xb5\\xfe";console.log(\\u00b5\\u00fe);'
|
||||
expect_stdout: "µþ"
|
||||
}
|
||||
|
||||
non_escape_2_non_escape: {
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
}
|
||||
input: {
|
||||
var µþ = "µþ";
|
||||
console.log(\u00b5þ);
|
||||
}
|
||||
expect_exact: 'var µþ="µþ";console.log(µþ);'
|
||||
expect_stdout: "µþ"
|
||||
}
|
||||
|
||||
issue_2242_1: {
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
@@ -24,6 +99,7 @@ issue_2242_1: {
|
||||
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
|
||||
}
|
||||
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
|
||||
expect_stdout: "\ud83d \ude00 \ud83d\ude00 \ud83d@\ude00"
|
||||
}
|
||||
|
||||
issue_2242_2: {
|
||||
@@ -34,6 +110,7 @@ issue_2242_2: {
|
||||
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
|
||||
}
|
||||
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
|
||||
expect_stdout: "\ud83d \ude00 \ud83d\ude00 \ud83d@\ude00"
|
||||
}
|
||||
|
||||
issue_2242_3: {
|
||||
@@ -44,6 +121,7 @@ issue_2242_3: {
|
||||
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
|
||||
}
|
||||
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
|
||||
expect_stdout: "\ud83d\ude00 \ud83d@\ude00"
|
||||
}
|
||||
|
||||
issue_2242_4: {
|
||||
@@ -54,6 +132,7 @@ issue_2242_4: {
|
||||
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
|
||||
}
|
||||
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
|
||||
expect_stdout: "\ud83d\ude00 \ud83d@\ude00"
|
||||
}
|
||||
|
||||
issue_2569: {
|
||||
|
||||
17
test/input/issue-1482/beautify.js
Normal file
17
test/input/issue-1482/beautify.js
Normal file
@@ -0,0 +1,17 @@
|
||||
if (x) foo();
|
||||
|
||||
if (x) foo(); else baz();
|
||||
|
||||
if (x) foo(); else if (y) bar(); else baz();
|
||||
|
||||
if (x) if (y) foo(); else bar(); else baz();
|
||||
|
||||
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
|
||||
|
||||
function f() {
|
||||
if (x) foo();
|
||||
if (x) foo(); else baz();
|
||||
if (x) foo(); else if (y) bar(); else baz();
|
||||
if (x) if (y) foo(); else bar(); else baz();
|
||||
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
|
||||
}
|
||||
@@ -1,17 +1 @@
|
||||
if (x) foo();
|
||||
|
||||
if (x) foo(); else baz();
|
||||
|
||||
if (x) foo(); else if (y) bar(); else baz();
|
||||
|
||||
if (x) if (y) foo(); else bar(); else baz();
|
||||
|
||||
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
|
||||
|
||||
function f() {
|
||||
if (x) foo();
|
||||
if (x) foo(); else baz();
|
||||
if (x) foo(); else if (y) bar(); else baz();
|
||||
if (x) if (y) foo(); else bar(); else baz();
|
||||
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
|
||||
}
|
||||
if(x)foo();if(x)foo();else baz();if(x)foo();else if(y)bar();else baz();if(x)if(y)foo();else bar();else baz();if(x)foo();else if(y)bar();else if(z)baz();else moo();function f(){if(x)foo();if(x)foo();else baz();if(x)foo();else if(y)bar();else baz();if(x)if(y)foo();else bar();else baz();if(x)foo();else if(y)bar();else if(z)baz();else moo()}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var fs = require("fs");
|
||||
|
||||
var config = {
|
||||
limit: 5000,
|
||||
limit: 10000,
|
||||
timeout: function(limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
@@ -55,11 +55,11 @@ process.nextTick(function run() {
|
||||
var elapsed = Date.now();
|
||||
var timer;
|
||||
var done = function() {
|
||||
reset();
|
||||
elapsed = Date.now() - elapsed;
|
||||
if (elapsed > task.limit) {
|
||||
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
|
||||
}
|
||||
reset();
|
||||
log_titles(console.log, task.titles, green('\u221A '));
|
||||
process.nextTick(run);
|
||||
};
|
||||
|
||||
@@ -176,7 +176,7 @@ describe("bin/uglifyjs", function() {
|
||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
|
||||
assert.strictEqual(stdout, read("test/input/issue-1482/beautify.js"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -188,6 +188,22 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with `--output-opts`", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -O';
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should fail when both --beautify & --output-opts are specified", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-520/input.js -bO";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stderr, "ERROR: --beautify cannot be used with --output-opts\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should process inline source map", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
|
||||
@@ -1090,9 +1090,10 @@ function log(options) {
|
||||
}
|
||||
|
||||
function fuzzy_match(original, uglified) {
|
||||
original = original.split(" ", 5);
|
||||
uglified = uglified.split(" ", 5);
|
||||
for (var i = 0; i < 5; i++) {
|
||||
uglified = uglified.split(" ");
|
||||
var i = uglified.length;
|
||||
original = original.split(" ", i);
|
||||
while (--i >= 0) {
|
||||
if (original[i] === uglified[i]) continue;
|
||||
var a = +original[i];
|
||||
var b = +uglified[i];
|
||||
@@ -1128,7 +1129,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
ok = fuzzy_match(original_result, uglify_result);
|
||||
if (!ok) {
|
||||
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"));
|
||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result, o.toplevel);
|
||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user