Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30a75049f5 | ||
|
|
a3cc3a9b87 | ||
|
|
96f8befdd7 | ||
|
|
cd58635dcc | ||
|
|
274331d0ea | ||
|
|
0489d6de64 | ||
|
|
fb092839c2 | ||
|
|
b7c112eefe | ||
|
|
b2b8a0d386 | ||
|
|
ac40301813 | ||
|
|
3563d8c09e | ||
|
|
5ae04b3545 | ||
|
|
a80b228d8b | ||
|
|
cf4bf4ceb1 | ||
|
|
8223b2e0db | ||
|
|
381bd3836e |
10
README.md
10
README.md
@@ -68,7 +68,8 @@ The available options are:
|
||||
--source-map-inline Write base64-encoded source map to the end of js output.
|
||||
--in-source-map Input source map, useful if you're compressing
|
||||
JS that was generated from some other original
|
||||
code.
|
||||
code. Specify "inline" if the source map is included
|
||||
inline with the sources.
|
||||
--screw-ie8 Use this flag if you don't wish to support
|
||||
Internet Explorer 6/7/8.
|
||||
By default UglifyJS will not try to be IE-proof.
|
||||
@@ -200,9 +201,10 @@ compressed JS by mapping every token in the compiled JS to its original
|
||||
location.
|
||||
|
||||
To use this feature you need to pass `--in-source-map
|
||||
/path/to/input/source.map`. Normally the input source map should also point
|
||||
to the file containing the generated JS, so if that's correct you can omit
|
||||
input files from the command line.
|
||||
/path/to/input/source.map` or `--in-source-map inline` if the source map is
|
||||
included inline with the sources. Normally the input source map should also
|
||||
point to the file containing the generated JS, so if that's correct you can
|
||||
omit input files from the command line.
|
||||
|
||||
## Mangler options
|
||||
|
||||
|
||||
@@ -984,8 +984,8 @@ TreeWalker.prototype = {
|
||||
push: function (node) {
|
||||
if (node instanceof AST_Lambda) {
|
||||
this.directives = Object.create(this.directives);
|
||||
} else if (node instanceof AST_Directive) {
|
||||
this.directives[node.value] = this.directives[node.value] ? "up" : true;
|
||||
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
|
||||
this.directives[node.value] = node;
|
||||
}
|
||||
this.stack.push(node);
|
||||
},
|
||||
@@ -1013,7 +1013,7 @@ TreeWalker.prototype = {
|
||||
for (var i = 0; i < node.body.length; ++i) {
|
||||
var st = node.body[i];
|
||||
if (!(st instanceof AST_Directive)) break;
|
||||
if (st.value == type) return true;
|
||||
if (st.value == type) return st;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
437
lib/compress.js
437
lib/compress.js
@@ -98,10 +98,10 @@ function Compressor(options, false_by_default) {
|
||||
this.top_retain = function(def) {
|
||||
return top_retain.test(def.name);
|
||||
};
|
||||
} else if (typeof top_retain === "function") {
|
||||
} else if (typeof top_retain == "function") {
|
||||
this.top_retain = top_retain;
|
||||
} else if (top_retain) {
|
||||
if (typeof top_retain === "string") {
|
||||
if (typeof top_retain == "string") {
|
||||
top_retain = top_retain.split(/,/);
|
||||
}
|
||||
this.top_retain = function(def) {
|
||||
@@ -151,14 +151,25 @@ merge(Compressor.prototype, {
|
||||
node = node.hoist_declarations(this);
|
||||
was_scope = true;
|
||||
}
|
||||
// Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
|
||||
// would call AST_Node.transform() if a different instance of AST_Node is
|
||||
// produced after OPT().
|
||||
// This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
|
||||
// Migrate and defer all children's AST_Node.transform() to below, which
|
||||
// will now happen after this parent AST_Node has been properly substituted
|
||||
// thus gives a consistent AST snapshot.
|
||||
descend(node, this);
|
||||
node = node.optimize(this);
|
||||
if (was_scope && node instanceof AST_Scope) {
|
||||
node.drop_unused(this);
|
||||
descend(node, this);
|
||||
// Existing code relies on how AST_Node.optimize() worked, and omitting the
|
||||
// following replacement call would result in degraded efficiency of both
|
||||
// output and performance.
|
||||
descend(node, this);
|
||||
var opt = node.optimize(this);
|
||||
if (was_scope && opt instanceof AST_Scope) {
|
||||
opt.drop_unused(this);
|
||||
descend(opt, this);
|
||||
}
|
||||
node._squeezed = true;
|
||||
return node;
|
||||
if (opt === node) opt._squeezed = true;
|
||||
return opt;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -171,8 +182,7 @@ merge(Compressor.prototype, {
|
||||
if (compressor.has_directive("use asm")) return self;
|
||||
var opt = optimizer(self, compressor);
|
||||
opt._optimized = true;
|
||||
if (opt === self) return opt;
|
||||
return opt.transform(compressor);
|
||||
return opt;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -384,7 +394,7 @@ merge(Compressor.prototype, {
|
||||
return new ctor(props);
|
||||
};
|
||||
|
||||
function make_node_from_constant(compressor, val, orig) {
|
||||
function make_node_from_constant(val, orig) {
|
||||
switch (typeof val) {
|
||||
case "string":
|
||||
return make_node(AST_String, orig, {
|
||||
@@ -404,9 +414,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
return make_node(AST_Number, orig, { value: val });
|
||||
case "boolean":
|
||||
return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
|
||||
return make_node(val ? AST_True : AST_False, orig);
|
||||
case "undefined":
|
||||
return make_node(AST_Undefined, orig).transform(compressor);
|
||||
return make_node(AST_Undefined, orig);
|
||||
default:
|
||||
if (val === null) {
|
||||
return make_node(AST_Null, orig, { value: null });
|
||||
@@ -511,6 +521,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
var self = compressor.self();
|
||||
var var_defs_removed = false;
|
||||
var toplevel = compressor.option("toplevel");
|
||||
for (var stat_index = statements.length; --stat_index >= 0;) {
|
||||
var stat = statements[stat_index];
|
||||
if (stat instanceof AST_Definitions) continue;
|
||||
@@ -548,7 +559,8 @@ merge(Compressor.prototype, {
|
||||
|
||||
// Only interested in cases with just one reference to the variable.
|
||||
var def = self.find_variable && self.find_variable(var_name);
|
||||
if (!def || !def.references || def.references.length !== 1 || var_name == "arguments") {
|
||||
if (!def || !def.references || def.references.length !== 1
|
||||
|| var_name == "arguments" || (!toplevel && def.global)) {
|
||||
side_effects_encountered = true;
|
||||
continue;
|
||||
}
|
||||
@@ -914,7 +926,7 @@ merge(Compressor.prototype, {
|
||||
if (stat instanceof AST_LoopControl) {
|
||||
var lct = compressor.loopcontrol_target(stat.label);
|
||||
if ((stat instanceof AST_Break
|
||||
&& lct instanceof AST_BlockStatement
|
||||
&& !(lct instanceof AST_IterationStatement)
|
||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
||||
&& loop_body(lct) === self)) {
|
||||
if (stat.label) {
|
||||
@@ -1198,11 +1210,11 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
});
|
||||
function to_node(compressor, value, orig) {
|
||||
function to_node(value, orig) {
|
||||
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
||||
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
||||
elements: value.map(function(value) {
|
||||
return to_node(compressor, value, orig);
|
||||
return to_node(value, orig);
|
||||
})
|
||||
});
|
||||
if (value && typeof value == "object") {
|
||||
@@ -1210,14 +1222,14 @@ merge(Compressor.prototype, {
|
||||
for (var key in value) {
|
||||
props.push(make_node(AST_ObjectKeyVal, orig, {
|
||||
key: key,
|
||||
value: to_node(compressor, value[key], orig)
|
||||
value: to_node(value[key], orig)
|
||||
}));
|
||||
}
|
||||
return make_node(AST_Object, orig, {
|
||||
properties: props
|
||||
});
|
||||
}
|
||||
return make_node_from_constant(compressor, value, orig);
|
||||
return make_node_from_constant(value, orig);
|
||||
}
|
||||
def(AST_Node, noop);
|
||||
def(AST_Dot, function(compressor, suffix){
|
||||
@@ -1228,7 +1240,7 @@ merge(Compressor.prototype, {
|
||||
var name;
|
||||
var defines = compressor.option("global_defs");
|
||||
if (defines && HOP(defines, (name = this.name + suffix))) {
|
||||
var node = to_node(compressor, defines[name], this);
|
||||
var node = to_node(defines[name], this);
|
||||
var top = compressor.find_parent(AST_Toplevel);
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
@@ -1243,45 +1255,40 @@ merge(Compressor.prototype, {
|
||||
node.DEFMETHOD("_find_defs", func);
|
||||
});
|
||||
|
||||
function best_of(ast1, ast2) {
|
||||
function best_of_expression(ast1, ast2) {
|
||||
return ast1.print_to_string().length >
|
||||
ast2.print_to_string().length
|
||||
? ast2 : ast1;
|
||||
}
|
||||
|
||||
function best_of_statement(ast1, ast2) {
|
||||
return best_of(make_node(AST_SimpleStatement, ast1, {
|
||||
return best_of_expression(make_node(AST_SimpleStatement, ast1, {
|
||||
body: ast1
|
||||
}), make_node(AST_SimpleStatement, ast2, {
|
||||
body: ast2
|
||||
})).body;
|
||||
}
|
||||
|
||||
function best_of(compressor, ast1, ast2) {
|
||||
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2);
|
||||
}
|
||||
|
||||
// methods to evaluate a constant expression
|
||||
(function (def){
|
||||
// The evaluate method returns an array with one or two
|
||||
// elements. If the node has been successfully reduced to a
|
||||
// constant, then the second element tells us the value;
|
||||
// otherwise the second element is missing. The first element
|
||||
// of the array is always an AST_Node descendant; if
|
||||
// evaluation was successful it's a node that represents the
|
||||
// constant; otherwise it's the original or a replacement node.
|
||||
// If the node has been successfully reduced to a constant,
|
||||
// then its value is returned; otherwise the element itself
|
||||
// is returned.
|
||||
// They can be distinguished as constant value is never a
|
||||
// descendant of AST_Node.
|
||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||
if (!compressor.option("evaluate")) return [ this ];
|
||||
var val;
|
||||
if (!compressor.option("evaluate")) return this;
|
||||
try {
|
||||
val = this._eval(compressor);
|
||||
var val = this._eval(compressor);
|
||||
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
||||
} catch(ex) {
|
||||
if (ex !== def) throw ex;
|
||||
return [ this ];
|
||||
return this;
|
||||
}
|
||||
var node;
|
||||
try {
|
||||
node = make_node_from_constant(compressor, val, this);
|
||||
} catch(ex) {
|
||||
return [ this ];
|
||||
}
|
||||
return [ best_of(node, this), val ];
|
||||
});
|
||||
var unaryPrefix = makePredicate("! ~ - +");
|
||||
AST_Node.DEFMETHOD("is_constant", function(){
|
||||
@@ -1319,8 +1326,8 @@ merge(Compressor.prototype, {
|
||||
}));
|
||||
}
|
||||
var result = this.evaluate(compressor);
|
||||
if (result.length > 1) {
|
||||
return result[1];
|
||||
if (result !== this) {
|
||||
return result;
|
||||
}
|
||||
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
||||
});
|
||||
@@ -1480,9 +1487,9 @@ merge(Compressor.prototype, {
|
||||
var stat = make_node(AST_SimpleStatement, alt, {
|
||||
body: alt
|
||||
});
|
||||
return best_of(negated, stat) === stat ? alt : negated;
|
||||
return best_of_expression(negated, stat) === stat ? alt : negated;
|
||||
}
|
||||
return best_of(negated, alt);
|
||||
return best_of_expression(negated, alt);
|
||||
}
|
||||
def(AST_Node, function(){
|
||||
return basic_negation(this);
|
||||
@@ -1646,8 +1653,8 @@ merge(Compressor.prototype, {
|
||||
return thing && thing.aborts();
|
||||
};
|
||||
(function(def){
|
||||
def(AST_Statement, function(){ return null });
|
||||
def(AST_Jump, function(){ return this });
|
||||
def(AST_Statement, return_null);
|
||||
def(AST_Jump, return_this);
|
||||
function block_aborts(){
|
||||
var n = this.body.length;
|
||||
return n > 0 && aborts(this.body[n - 1]);
|
||||
@@ -1664,7 +1671,7 @@ merge(Compressor.prototype, {
|
||||
/* -----[ optimizers ]----- */
|
||||
|
||||
OPT(AST_Directive, function(self, compressor){
|
||||
if (compressor.has_directive(self.value) === "up") {
|
||||
if (compressor.has_directive(self.value) !== self) {
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
}
|
||||
return self;
|
||||
@@ -1981,7 +1988,7 @@ merge(Compressor.prototype, {
|
||||
vars.set(def.name.name, def);
|
||||
++vars_found;
|
||||
});
|
||||
var seq = node.to_assignments();
|
||||
var seq = node.to_assignments(compressor);
|
||||
var p = tt.parent();
|
||||
if (p instanceof AST_ForIn && p.init === node) {
|
||||
if (seq == null) {
|
||||
@@ -2077,14 +2084,6 @@ merge(Compressor.prototype, {
|
||||
// drop_side_effect_free()
|
||||
// remove side-effect-free parts which only affects return value
|
||||
(function(def){
|
||||
function return_this() {
|
||||
return this;
|
||||
}
|
||||
|
||||
function return_null() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Drop side-effect-free elements from an array of expressions.
|
||||
// Returns an array of expressions with side-effects or null
|
||||
// if all elements were dropped. Note: original array may be
|
||||
@@ -2241,27 +2240,24 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_DWLoop, function(self, compressor){
|
||||
var cond = self.condition.evaluate(compressor);
|
||||
self.condition = cond[0];
|
||||
if (!compressor.option("loops")) return self;
|
||||
if (cond.length > 1) {
|
||||
if (cond[1]) {
|
||||
var cond = self.condition.evaluate(compressor);
|
||||
if (cond !== self.condition) {
|
||||
if (cond) {
|
||||
return make_node(AST_For, self, {
|
||||
body: self.body
|
||||
});
|
||||
} else if (self instanceof AST_While) {
|
||||
if (compressor.option("dead_code")) {
|
||||
var a = [];
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
return make_node(AST_BlockStatement, self, { body: a });
|
||||
}
|
||||
} else if (compressor.option("dead_code") && self instanceof AST_While) {
|
||||
var a = [];
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
return make_node(AST_BlockStatement, self, { body: a });
|
||||
} else {
|
||||
// self instanceof AST_Do
|
||||
return self;
|
||||
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||
self.condition = best_of_expression(cond, self.condition);
|
||||
}
|
||||
}
|
||||
if (self instanceof AST_While) {
|
||||
return make_node(AST_For, self, self).transform(compressor);
|
||||
return make_node(AST_For, self, self).optimize(compressor);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
@@ -2283,7 +2279,7 @@ merge(Compressor.prototype, {
|
||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
||||
if (first instanceof AST_If) {
|
||||
if (first.body instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.body.label) === self) {
|
||||
&& compressor.loopcontrol_target(first.body.label) === compressor.self()) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -2296,7 +2292,7 @@ merge(Compressor.prototype, {
|
||||
drop_it(first.alternative);
|
||||
}
|
||||
else if (first.alternative instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(first.alternative.label) === self) {
|
||||
&& compressor.loopcontrol_target(first.alternative.label) === compressor.self()) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -2312,27 +2308,25 @@ merge(Compressor.prototype, {
|
||||
};
|
||||
|
||||
OPT(AST_For, function(self, compressor){
|
||||
var cond = self.condition;
|
||||
if (cond) {
|
||||
cond = cond.evaluate(compressor);
|
||||
self.condition = cond[0];
|
||||
}
|
||||
if (!compressor.option("loops")) return self;
|
||||
if (cond) {
|
||||
if (cond.length > 1 && !cond[1]) {
|
||||
if (compressor.option("dead_code")) {
|
||||
var a = [];
|
||||
if (self.init instanceof AST_Statement) {
|
||||
a.push(self.init);
|
||||
}
|
||||
else if (self.init) {
|
||||
a.push(make_node(AST_SimpleStatement, self.init, {
|
||||
body: self.init
|
||||
}));
|
||||
}
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
return make_node(AST_BlockStatement, self, { body: a });
|
||||
if (self.condition) {
|
||||
var cond = self.condition.evaluate(compressor);
|
||||
if (compressor.option("dead_code") && !cond) {
|
||||
var a = [];
|
||||
if (self.init instanceof AST_Statement) {
|
||||
a.push(self.init);
|
||||
}
|
||||
else if (self.init) {
|
||||
a.push(make_node(AST_SimpleStatement, self.init, {
|
||||
body: self.init
|
||||
}));
|
||||
}
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
return make_node(AST_BlockStatement, self, { body: a });
|
||||
}
|
||||
if (cond !== self.condition) {
|
||||
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||
self.condition = best_of_expression(cond, self.condition);
|
||||
}
|
||||
}
|
||||
if_break_in_loop(self, compressor);
|
||||
@@ -2348,9 +2342,8 @@ merge(Compressor.prototype, {
|
||||
// “has no side effects”; also it doesn't work for cases like
|
||||
// `x && true`, though it probably should.
|
||||
var cond = self.condition.evaluate(compressor);
|
||||
self.condition = cond[0];
|
||||
if (cond.length > 1) {
|
||||
if (cond[1]) {
|
||||
if (cond !== self.condition) {
|
||||
if (cond) {
|
||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
|
||||
if (compressor.option("dead_code")) {
|
||||
var a = [];
|
||||
@@ -2358,7 +2351,7 @@ merge(Compressor.prototype, {
|
||||
extract_declarations_from_unreachable_code(compressor, self.alternative, a);
|
||||
}
|
||||
a.push(self.body);
|
||||
return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
|
||||
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
|
||||
}
|
||||
} else {
|
||||
compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
||||
@@ -2366,9 +2359,11 @@ merge(Compressor.prototype, {
|
||||
var a = [];
|
||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||
if (self.alternative) a.push(self.alternative);
|
||||
return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
|
||||
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
|
||||
}
|
||||
}
|
||||
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||
self.condition = best_of_expression(cond, self.condition);
|
||||
}
|
||||
var negated = self.condition.negate(compressor);
|
||||
var self_condition_length = self.condition.print_to_string().length;
|
||||
@@ -2385,8 +2380,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (is_empty(self.body) && is_empty(self.alternative)) {
|
||||
return make_node(AST_SimpleStatement, self.condition, {
|
||||
body: self.condition
|
||||
}).transform(compressor);
|
||||
body: self.condition.clone()
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (self.body instanceof AST_SimpleStatement
|
||||
&& self.alternative instanceof AST_SimpleStatement) {
|
||||
@@ -2396,7 +2391,7 @@ merge(Compressor.prototype, {
|
||||
consequent : statement_to_expression(self.body),
|
||||
alternative : statement_to_expression(self.alternative)
|
||||
})
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
|
||||
if (self_condition_length === negated_length && !negated_is_best
|
||||
@@ -2412,14 +2407,14 @@ merge(Compressor.prototype, {
|
||||
left : negated,
|
||||
right : statement_to_expression(self.body)
|
||||
})
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
return make_node(AST_SimpleStatement, self, {
|
||||
body: make_node(AST_Binary, self, {
|
||||
operator : "&&",
|
||||
left : self.condition,
|
||||
right : statement_to_expression(self.body)
|
||||
})
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (self.body instanceof AST_EmptyStatement
|
||||
&& self.alternative
|
||||
@@ -2430,7 +2425,7 @@ merge(Compressor.prototype, {
|
||||
left : self.condition,
|
||||
right : statement_to_expression(self.alternative)
|
||||
})
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (self.body instanceof AST_Exit
|
||||
&& self.alternative instanceof AST_Exit
|
||||
@@ -2440,18 +2435,21 @@ merge(Compressor.prototype, {
|
||||
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);
|
||||
}).transform(compressor)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (self.body instanceof AST_If
|
||||
&& !self.body.alternative
|
||||
&& !self.alternative) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
operator: "&&",
|
||||
left: self.condition,
|
||||
right: self.body.condition
|
||||
}).transform(compressor);
|
||||
self.body = self.body.body;
|
||||
self = make_node(AST_If, self, {
|
||||
condition: make_node(AST_Binary, self.condition, {
|
||||
operator: "&&",
|
||||
left: self.condition,
|
||||
right: self.body.condition
|
||||
}),
|
||||
body: self.body.body,
|
||||
alternative: null
|
||||
});
|
||||
}
|
||||
if (aborts(self.body)) {
|
||||
if (self.alternative) {
|
||||
@@ -2459,7 +2457,7 @@ merge(Compressor.prototype, {
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: [ self, alt ]
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (aborts(self.alternative)) {
|
||||
@@ -2469,7 +2467,7 @@ merge(Compressor.prototype, {
|
||||
self.alternative = null;
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: [ self, body ]
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
@@ -2493,12 +2491,12 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
}
|
||||
var exp = self.expression.evaluate(compressor);
|
||||
out: if (exp.length == 2) try {
|
||||
var value = self.expression.evaluate(compressor);
|
||||
out: if (value !== self.expression) try {
|
||||
// constant expression
|
||||
self.expression = exp[0];
|
||||
var expression = make_node_from_constant(value, self.expression);
|
||||
self.expression = best_of_expression(expression, self.expression);
|
||||
if (!compressor.option("dead_code")) break out;
|
||||
var value = exp[1];
|
||||
var in_if = false;
|
||||
var in_block = false;
|
||||
var started = false;
|
||||
@@ -2545,11 +2543,11 @@ merge(Compressor.prototype, {
|
||||
if (stopped) return MAP.skip;
|
||||
if (node instanceof AST_Case) {
|
||||
var exp = node.expression.evaluate(compressor);
|
||||
if (exp.length < 2) {
|
||||
if (exp === node.expression) {
|
||||
// got a case with non-constant expression, baling out
|
||||
throw self;
|
||||
}
|
||||
if (exp[1] === value || started) {
|
||||
if (exp === value || started) {
|
||||
started = true;
|
||||
if (aborts(node)) stopped = true;
|
||||
descend(node, this);
|
||||
@@ -2583,7 +2581,8 @@ merge(Compressor.prototype, {
|
||||
this.definitions.forEach(function(def){ def.value = null });
|
||||
});
|
||||
|
||||
AST_Definitions.DEFMETHOD("to_assignments", function(){
|
||||
AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
|
||||
var reduce_vars = compressor.option("reduce_vars");
|
||||
var assignments = this.definitions.reduce(function(a, def){
|
||||
if (def.value) {
|
||||
var name = make_node(AST_SymbolRef, def.name, def.name);
|
||||
@@ -2592,6 +2591,7 @@ merge(Compressor.prototype, {
|
||||
left : name,
|
||||
right : def.value
|
||||
}));
|
||||
if (reduce_vars) name.definition().fixed = false;
|
||||
}
|
||||
return a;
|
||||
}, []);
|
||||
@@ -2656,7 +2656,7 @@ merge(Compressor.prototype, {
|
||||
if (self.args.length != 1) {
|
||||
return make_node(AST_Array, self, {
|
||||
elements: self.args
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "Object":
|
||||
@@ -2674,7 +2674,7 @@ merge(Compressor.prototype, {
|
||||
left: self.args[0],
|
||||
operator: "+",
|
||||
right: make_node(AST_String, self, { value: "" })
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
break;
|
||||
case "Number":
|
||||
if (self.args.length == 0) return make_node(AST_Number, self, {
|
||||
@@ -2683,7 +2683,7 @@ merge(Compressor.prototype, {
|
||||
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
|
||||
expression: self.args[0],
|
||||
operator: "+"
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
case "Boolean":
|
||||
if (self.args.length == 0) return make_node(AST_False, self);
|
||||
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
|
||||
@@ -2692,7 +2692,7 @@ merge(Compressor.prototype, {
|
||||
operator: "!"
|
||||
}),
|
||||
operator: "!"
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
break;
|
||||
case "Function":
|
||||
// new Function() => function(){}
|
||||
@@ -2757,21 +2757,20 @@ merge(Compressor.prototype, {
|
||||
left: make_node(AST_String, self, { value: "" }),
|
||||
operator: "+",
|
||||
right: exp.expression
|
||||
}).transform(compressor);
|
||||
}).optimize(compressor);
|
||||
}
|
||||
else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
|
||||
var separator;
|
||||
if (self.args.length > 0) {
|
||||
separator = self.args[0].evaluate(compressor);
|
||||
if (separator.length < 2) break EXIT; // not a constant
|
||||
separator = separator[1];
|
||||
if (separator === self.args[0]) break EXIT; // not a constant
|
||||
}
|
||||
var elements = [];
|
||||
var consts = [];
|
||||
exp.expression.elements.forEach(function(el) {
|
||||
el = el.evaluate(compressor);
|
||||
if (el.length > 1) {
|
||||
consts.push(el[1]);
|
||||
var value = el.evaluate(compressor);
|
||||
if (value !== el) {
|
||||
consts.push(value);
|
||||
} else {
|
||||
if (consts.length > 0) {
|
||||
elements.push(make_node(AST_String, self, {
|
||||
@@ -2779,7 +2778,7 @@ merge(Compressor.prototype, {
|
||||
}));
|
||||
consts.length = 0;
|
||||
}
|
||||
elements.push(el[0]);
|
||||
elements.push(el);
|
||||
}
|
||||
});
|
||||
if (consts.length > 0) {
|
||||
@@ -2812,7 +2811,7 @@ merge(Compressor.prototype, {
|
||||
left : prev,
|
||||
right : el
|
||||
});
|
||||
}, first).transform(compressor);
|
||||
}, first).optimize(compressor);
|
||||
}
|
||||
// need this awkward cloning to not affect original element
|
||||
// best_of will decide which one to get through.
|
||||
@@ -2820,7 +2819,17 @@ merge(Compressor.prototype, {
|
||||
node.expression = node.expression.clone();
|
||||
node.expression.expression = node.expression.expression.clone();
|
||||
node.expression.expression.elements = elements;
|
||||
return best_of(self, node);
|
||||
return best_of(compressor, self, node);
|
||||
}
|
||||
else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") {
|
||||
var arg = self.args[0];
|
||||
var index = arg ? arg.evaluate(compressor) : 0;
|
||||
if (index !== arg) {
|
||||
return make_node(AST_Sub, exp, {
|
||||
expression: exp.expression,
|
||||
property: make_node_from_constant(index | 0, arg || exp)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exp instanceof AST_Function) {
|
||||
@@ -2966,8 +2975,7 @@ merge(Compressor.prototype, {
|
||||
return e.expression;
|
||||
}
|
||||
if (e instanceof AST_Binary) {
|
||||
var statement = first_in_statement(compressor);
|
||||
self = (statement ? best_of_statement : best_of)(self, e.negate(compressor, statement));
|
||||
self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
|
||||
}
|
||||
break;
|
||||
case "typeof":
|
||||
@@ -2980,17 +2988,17 @@ merge(Compressor.prototype, {
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
return self.evaluate(compressor)[0];
|
||||
// avoids infinite recursion of numerals
|
||||
if (self.operator != "-" || !(self.expression instanceof AST_Number)) {
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
function has_side_effects_or_prop_access(node, compressor) {
|
||||
var save_pure_getters = compressor.option("pure_getters");
|
||||
compressor.options.pure_getters = false;
|
||||
var ret = node.has_side_effects(compressor);
|
||||
compressor.options.pure_getters = save_pure_getters;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
|
||||
if (compressor.option("sequences")) {
|
||||
if (this.left instanceof AST_Seq) {
|
||||
@@ -2998,18 +3006,23 @@ merge(Compressor.prototype, {
|
||||
var x = seq.to_array();
|
||||
this.left = x.pop();
|
||||
x.push(this);
|
||||
seq = AST_Seq.from_array(x).transform(compressor);
|
||||
return seq;
|
||||
return AST_Seq.from_array(x).optimize(compressor);
|
||||
}
|
||||
if (this.right instanceof AST_Seq
|
||||
&& this instanceof AST_Assign
|
||||
&& !has_side_effects_or_prop_access(this.left, compressor)) {
|
||||
var seq = this.right;
|
||||
var x = seq.to_array();
|
||||
this.right = x.pop();
|
||||
x.push(this);
|
||||
seq = AST_Seq.from_array(x).transform(compressor);
|
||||
return seq;
|
||||
if (this.right instanceof AST_Seq && !this.left.has_side_effects(compressor)) {
|
||||
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
||||
var root = this.right;
|
||||
var cursor, seq = root;
|
||||
while (assign || !seq.car.has_side_effects(compressor)) {
|
||||
cursor = seq;
|
||||
if (seq.cdr instanceof AST_Seq) {
|
||||
seq = seq.cdr;
|
||||
} else break;
|
||||
}
|
||||
if (cursor) {
|
||||
this.right = cursor.cdr;
|
||||
cursor.cdr = this;
|
||||
return root.optimize(compressor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -3018,16 +3031,6 @@ merge(Compressor.prototype, {
|
||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||
|
||||
OPT(AST_Binary, function(self, compressor){
|
||||
var lhs = self.left.evaluate(compressor);
|
||||
var rhs = self.right.evaluate(compressor);
|
||||
if (lhs.length > 1 && lhs[0].is_constant() !== self.left.is_constant()
|
||||
|| rhs.length > 1 && rhs[0].is_constant() !== self.right.is_constant()) {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: self.operator,
|
||||
left: lhs[0],
|
||||
right: rhs[0]
|
||||
}).optimize(compressor);
|
||||
}
|
||||
function reversible() {
|
||||
return self.left instanceof AST_Constant
|
||||
|| self.right instanceof AST_Constant
|
||||
@@ -3054,32 +3057,6 @@ merge(Compressor.prototype, {
|
||||
reverse();
|
||||
}
|
||||
}
|
||||
if (/^[!=]==?$/.test(self.operator)) {
|
||||
if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) {
|
||||
if (self.right.consequent instanceof AST_SymbolRef
|
||||
&& self.right.consequent.definition() === self.left.definition()) {
|
||||
if (/^==/.test(self.operator)) return self.right.condition;
|
||||
if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor);
|
||||
}
|
||||
if (self.right.alternative instanceof AST_SymbolRef
|
||||
&& self.right.alternative.definition() === self.left.definition()) {
|
||||
if (/^==/.test(self.operator)) return self.right.condition.negate(compressor);
|
||||
if (/^!=/.test(self.operator)) return self.right.condition;
|
||||
}
|
||||
}
|
||||
if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) {
|
||||
if (self.left.consequent instanceof AST_SymbolRef
|
||||
&& self.left.consequent.definition() === self.right.definition()) {
|
||||
if (/^==/.test(self.operator)) return self.left.condition;
|
||||
if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor);
|
||||
}
|
||||
if (self.left.alternative instanceof AST_SymbolRef
|
||||
&& self.left.alternative.definition() === self.right.definition()) {
|
||||
if (/^==/.test(self.operator)) return self.left.condition.negate(compressor);
|
||||
if (/^!=/.test(self.operator)) return self.left.condition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self = self.lift_sequences(compressor);
|
||||
if (compressor.option("comparisons")) switch (self.operator) {
|
||||
@@ -3112,48 +3089,48 @@ merge(Compressor.prototype, {
|
||||
case "&&":
|
||||
var ll = self.left.evaluate(compressor);
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
|
||||
if (!ll || !rr) {
|
||||
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_False, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (ll.length > 1 && ll[1]) {
|
||||
return rr[0];
|
||||
if (ll !== self.left && ll) {
|
||||
return self.right.optimize(compressor);
|
||||
}
|
||||
if (rr.length > 1 && rr[1]) {
|
||||
return ll[0];
|
||||
if (rr !== self.right && rr) {
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "||":
|
||||
var ll = self.left.evaluate(compressor);
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
|
||||
if (ll !== self.left && ll || rr !== self.right && rr) {
|
||||
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (ll.length > 1 && !ll[1]) {
|
||||
return rr[0];
|
||||
if (!ll) {
|
||||
return self.right.optimize(compressor);
|
||||
}
|
||||
if (rr.length > 1 && !rr[1]) {
|
||||
return ll[0];
|
||||
if (!rr) {
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
break;
|
||||
case "+":
|
||||
var ll = self.left.evaluate(compressor);
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
|
||||
if (ll && typeof ll == "string") {
|
||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.right,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
|
||||
if (rr && typeof rr == "string") {
|
||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
@@ -3165,12 +3142,11 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("comparisons") && self.is_boolean()) {
|
||||
if (!(compressor.parent() instanceof AST_Binary)
|
||||
|| compressor.parent() instanceof AST_Assign) {
|
||||
var statement = first_in_statement(compressor);
|
||||
var negated = make_node(AST_UnaryPrefix, self, {
|
||||
operator: "!",
|
||||
expression: self.negate(compressor, statement)
|
||||
expression: self.negate(compressor, first_in_statement(compressor))
|
||||
});
|
||||
self = (statement ? best_of_statement : best_of)(self, negated);
|
||||
self = best_of(compressor, self, negated);
|
||||
}
|
||||
if (compressor.option("unsafe_comps")) {
|
||||
switch (self.operator) {
|
||||
@@ -3322,9 +3298,9 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
if (self.right instanceof AST_Constant
|
||||
&& !(self.left instanceof AST_Constant)) {
|
||||
self = best_of(reversed, self);
|
||||
self = best_of(compressor, reversed, self);
|
||||
} else {
|
||||
self = best_of(self, reversed);
|
||||
self = best_of(compressor, self, reversed);
|
||||
}
|
||||
}
|
||||
if (associative && self.is_number(compressor)) {
|
||||
@@ -3421,7 +3397,12 @@ merge(Compressor.prototype, {
|
||||
self.right = self.right.right;
|
||||
return self.transform(compressor);
|
||||
}
|
||||
return self.evaluate(compressor)[0];
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
OPT(AST_SymbolRef, function(self, compressor){
|
||||
@@ -3436,11 +3417,11 @@ merge(Compressor.prototype, {
|
||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||
switch (self.name) {
|
||||
case "undefined":
|
||||
return make_node(AST_Undefined, self).transform(compressor);
|
||||
return make_node(AST_Undefined, self).optimize(compressor);
|
||||
case "NaN":
|
||||
return make_node(AST_NaN, self).transform(compressor);
|
||||
return make_node(AST_NaN, self).optimize(compressor);
|
||||
case "Infinity":
|
||||
return make_node(AST_Infinity, self).transform(compressor);
|
||||
return make_node(AST_Infinity, self).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
||||
@@ -3448,18 +3429,20 @@ merge(Compressor.prototype, {
|
||||
if (d.fixed) {
|
||||
if (d.should_replace === undefined) {
|
||||
var init = d.fixed.evaluate(compressor);
|
||||
if (init.length > 1) {
|
||||
var value = init[0].print_to_string().length;
|
||||
if (init !== d.fixed) {
|
||||
init = make_node_from_constant(init, d.fixed).optimize(compressor);
|
||||
init = best_of_expression(init, d.fixed);
|
||||
var value = init.print_to_string().length;
|
||||
var name = d.name.length;
|
||||
var freq = d.references.length;
|
||||
var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq;
|
||||
d.should_replace = value <= name + overhead ? init[0] : false;
|
||||
d.should_replace = value <= name + overhead ? init : false;
|
||||
} else {
|
||||
d.should_replace = false;
|
||||
}
|
||||
}
|
||||
if (d.should_replace) {
|
||||
return d.should_replace;
|
||||
return d.should_replace.clone(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3524,8 +3507,8 @@ merge(Compressor.prototype, {
|
||||
return AST_Seq.cons(car, self);
|
||||
}
|
||||
var cond = self.condition.evaluate(compressor);
|
||||
if (cond.length > 1) {
|
||||
if (cond[1]) {
|
||||
if (cond !== self.condition) {
|
||||
if (cond) {
|
||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
||||
return maintain_this_binding(compressor.parent(), self, self.consequent);
|
||||
} else {
|
||||
@@ -3533,9 +3516,8 @@ merge(Compressor.prototype, {
|
||||
return maintain_this_binding(compressor.parent(), self, self.alternative);
|
||||
}
|
||||
}
|
||||
var statement = first_in_statement(compressor);
|
||||
var negated = cond[0].negate(compressor, statement);
|
||||
if ((statement ? best_of_statement : best_of)(cond[0], negated) === negated) {
|
||||
var negated = cond.negate(compressor, first_in_statement(compressor));
|
||||
if (best_of(compressor, cond, negated) === negated) {
|
||||
self = make_node(AST_Conditional, self, {
|
||||
condition: negated,
|
||||
consequent: self.alternative,
|
||||
@@ -3715,7 +3697,12 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
return self.evaluate(compressor)[0];
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
OPT(AST_Dot, function(self, compressor){
|
||||
@@ -3754,13 +3741,17 @@ merge(Compressor.prototype, {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return self.evaluate(compressor)[0];
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
function literals_in_boolean_context(self, compressor) {
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
var best = first_in_statement(compressor) ? best_of_statement : best_of;
|
||||
return best(self, make_node(AST_Seq, self, {
|
||||
return best_of(compressor, self, make_node(AST_Seq, self, {
|
||||
car: self,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor));
|
||||
|
||||
@@ -126,9 +126,11 @@ function merge(obj, ext) {
|
||||
return count;
|
||||
};
|
||||
|
||||
function noop() {};
|
||||
function noop() {}
|
||||
function return_false() { return false; }
|
||||
function return_true() { return true; }
|
||||
function return_this() { return this; }
|
||||
function return_null() { return null; }
|
||||
|
||||
var MAP = (function(){
|
||||
function MAP(a, f, backwards) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "http://lisperator.net/uglifyjs",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "2.8.12",
|
||||
"version": "2.8.14",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -43,6 +43,7 @@ collapse_vars_side_effects_1: {
|
||||
z = i += 4;
|
||||
log(x, z, y, i);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
expect: {
|
||||
function f1() {
|
||||
@@ -73,7 +74,9 @@ collapse_vars_side_effects_1: {
|
||||
y = i += 3;
|
||||
log(x, i += 4, y, i);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_side_effects_2: {
|
||||
@@ -823,6 +826,7 @@ collapse_vars_repeated: {
|
||||
console.log(e + "!");
|
||||
})("!");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_closures: {
|
||||
@@ -1109,6 +1113,7 @@ collapse_vars_eval_and_with: {
|
||||
return function() { with (o) console.log(a) };
|
||||
})()();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_constants: {
|
||||
@@ -1152,7 +1157,8 @@ collapse_vars_arguments: {
|
||||
options = {
|
||||
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
|
||||
toplevel:true
|
||||
}
|
||||
input: {
|
||||
var outer = function() {
|
||||
@@ -1167,6 +1173,7 @@ collapse_vars_arguments: {
|
||||
(function(){console.log(arguments);})(7, 1);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_short_circuit: {
|
||||
@@ -1316,6 +1323,7 @@ collapse_vars_regexp: {
|
||||
console.log(result[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1537: {
|
||||
@@ -1335,6 +1343,7 @@ issue_1537: {
|
||||
issue_1562: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var v = 1, B = 2;
|
||||
@@ -1363,3 +1372,46 @@ issue_1562: {
|
||||
for (; f(z + 2) ;) bar(30);
|
||||
}
|
||||
}
|
||||
|
||||
issue_1605_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
function foo(x) {
|
||||
var y = x;
|
||||
return y;
|
||||
}
|
||||
var o = new Object;
|
||||
o.p = 1;
|
||||
}
|
||||
expect: {
|
||||
function foo(x) {
|
||||
return x;
|
||||
}
|
||||
var o = new Object;
|
||||
o.p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
issue_1605_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: "vars",
|
||||
}
|
||||
input: {
|
||||
function foo(x) {
|
||||
var y = x;
|
||||
return y;
|
||||
}
|
||||
var o = new Object;
|
||||
o.p = 1;
|
||||
}
|
||||
expect: {
|
||||
function foo(x) {
|
||||
return x;
|
||||
}
|
||||
(new Object).p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ concat_2: {
|
||||
"1" + "2" + "3"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_3: {
|
||||
@@ -79,6 +80,7 @@ concat_3: {
|
||||
1 + 2 + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_4: {
|
||||
@@ -107,6 +109,7 @@ concat_4: {
|
||||
1 + "2" + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_5: {
|
||||
@@ -135,6 +138,7 @@ concat_5: {
|
||||
"1" + 2 + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_6: {
|
||||
@@ -163,6 +167,7 @@ concat_6: {
|
||||
"1" + "2" + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_7: {
|
||||
@@ -188,6 +193,7 @@ concat_7: {
|
||||
x += "foo"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_8: {
|
||||
@@ -213,4 +219,5 @@ concat_8: {
|
||||
x += "foo"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -797,3 +797,99 @@ no_evaluate: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
equality_conditionals_false: {
|
||||
options = {
|
||||
conditionals: false,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0);
|
||||
f(0, true, 0);
|
||||
f(1, 2, 3);
|
||||
f(1, null, 3);
|
||||
f(NaN);
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0),
|
||||
f(0, true, 0),
|
||||
f(1, 2, 3),
|
||||
f(1, null, 3),
|
||||
f(NaN),
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
equality_conditionals_true: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0);
|
||||
f(0, true, 0);
|
||||
f(1, 2, 3);
|
||||
f(1, null, 3);
|
||||
f(NaN);
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
(b, a == a),
|
||||
a == (b ? a : c),
|
||||
(b, a != a),
|
||||
a != (b ? a : c),
|
||||
(b, a === a),
|
||||
a === (b ? a : c),
|
||||
(b, a !== a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0),
|
||||
f(0, true, 0),
|
||||
f(1, 2, 3),
|
||||
f(1, null, 3),
|
||||
f(NaN),
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -162,4 +162,5 @@ regexp_literal_not_const: {
|
||||
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
var x = 10, y;
|
||||
var moo;
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_declaration: {
|
||||
@@ -113,6 +114,7 @@ dead_code_const_declaration: {
|
||||
var moo;
|
||||
function bar() {}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation: {
|
||||
@@ -140,6 +142,7 @@ dead_code_const_annotation: {
|
||||
var moo;
|
||||
function bar() {}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation_regex: {
|
||||
@@ -163,6 +166,7 @@ dead_code_const_annotation_regex: {
|
||||
var CONST_FOO_ANN = !1;
|
||||
CONST_FOO_ANN && console.log('reachable');
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation_complex_scope: {
|
||||
@@ -208,4 +212,5 @@ dead_code_const_annotation_complex_scope: {
|
||||
var meat = 'beef';
|
||||
var pork = 'bad';
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -200,6 +200,7 @@ negative_zero: {
|
||||
1 / (-0)
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
positive_zero: {
|
||||
@@ -220,6 +221,7 @@ positive_zero: {
|
||||
1 / (0)
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_constant: {
|
||||
@@ -243,6 +245,7 @@ unsafe_constant: {
|
||||
(void 0).a
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object: {
|
||||
@@ -266,6 +269,7 @@ unsafe_object: {
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_nested: {
|
||||
@@ -289,6 +293,7 @@ unsafe_object_nested: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_complex: {
|
||||
@@ -312,6 +317,7 @@ unsafe_object_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_repeated: {
|
||||
@@ -335,6 +341,7 @@ unsafe_object_repeated: {
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_accessor: {
|
||||
@@ -384,6 +391,7 @@ unsafe_function: {
|
||||
({a:{b:1},b:function(){}}).a.b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_integer_key: {
|
||||
@@ -411,6 +419,7 @@ unsafe_integer_key: {
|
||||
1["1"] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_integer_key_complex: {
|
||||
@@ -438,6 +447,7 @@ unsafe_integer_key_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_float_key: {
|
||||
@@ -465,6 +475,7 @@ unsafe_float_key: {
|
||||
1["3.14"] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_float_key_complex: {
|
||||
@@ -492,6 +503,7 @@ unsafe_float_key_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_array: {
|
||||
@@ -527,6 +539,7 @@ unsafe_array: {
|
||||
(void 0)[1] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_string: {
|
||||
@@ -554,6 +567,7 @@ unsafe_string: {
|
||||
"11"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_array_bad_index: {
|
||||
@@ -575,6 +589,7 @@ unsafe_array_bad_index: {
|
||||
[1, 2, 3, 4][3.14] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_string_bad_index: {
|
||||
@@ -596,6 +611,7 @@ unsafe_string_bad_index: {
|
||||
"1234"[3.14] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_prototype_function: {
|
||||
@@ -642,6 +658,7 @@ call_args: {
|
||||
console.log(1);
|
||||
+(1, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
call_args_drop_param: {
|
||||
@@ -663,6 +680,7 @@ call_args_drop_param: {
|
||||
console.log(1);
|
||||
+(b, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
in_boolean_context: {
|
||||
@@ -700,4 +718,74 @@ in_boolean_context: {
|
||||
(foo(), !1)
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"1234" + 1,
|
||||
"1234".charAt(0) + 1,
|
||||
"1234".charAt(6 - 5) + 1,
|
||||
("12" + "34").charAt(0) + 1,
|
||||
("12" + "34").charAt(6 - 5) + 1,
|
||||
[1, 2, 3, 4].join("").charAt(0) + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
"12341",
|
||||
"11",
|
||||
"21",
|
||||
"11",
|
||||
"21",
|
||||
"11"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt_bad_index: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"1234".charAt() + 1,
|
||||
"1234".charAt("a") + 1,
|
||||
"1234".charAt(3.14) + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
"11",
|
||||
"11",
|
||||
"41"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt_noop: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
s.charAt(0),
|
||||
"string".charAt(x)
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
s.charAt(0),
|
||||
"string".charAt(x)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ iifes_returning_constants_keep_fargs_true: {
|
||||
console.log(6);
|
||||
console.log((a(), b(), 6));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iifes_returning_constants_keep_fargs_false: {
|
||||
@@ -73,6 +74,7 @@ iifes_returning_constants_keep_fargs_false: {
|
||||
console.log(6);
|
||||
console.log((a(), b(), 6));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_485_crashing_1530: {
|
||||
|
||||
@@ -49,4 +49,3 @@ mangle_keep_fnames_true: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,4 +46,5 @@ string_plus_optimization: {
|
||||
}
|
||||
foo();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ issue_1321_no_debug: {
|
||||
x["a"] = 2 * x.b;
|
||||
console.log(x.b, x["a"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1321_debug: {
|
||||
@@ -33,6 +34,7 @@ issue_1321_debug: {
|
||||
x["_$foo$_"] = 2 * x.a;
|
||||
console.log(x.a, x["_$foo$_"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1321_with_quoted: {
|
||||
@@ -51,4 +53,5 @@ issue_1321_with_quoted: {
|
||||
x["b"] = 2 * x.a;
|
||||
console.log(x.a, x["b"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -42,4 +42,5 @@ conditional_false_stray_else_in_loop: {
|
||||
}
|
||||
}
|
||||
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
99
test/compress/issue-1588.js
Normal file
99
test/compress/issue-1588.js
Normal file
@@ -0,0 +1,99 @@
|
||||
screw_ie8: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
input: {
|
||||
try { throw "foo"; } catch (x) { console.log(x); }
|
||||
}
|
||||
expect_exact: 'try{throw"foo"}catch(o){console.log(o)}'
|
||||
expect_stdout: [
|
||||
"foo"
|
||||
]
|
||||
}
|
||||
|
||||
support_ie8: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
input: {
|
||||
try { throw "foo"; } catch (x) { console.log(x); }
|
||||
}
|
||||
expect_exact: 'try{throw"foo"}catch(x){console.log(x)}'
|
||||
expect_stdout: "foo"
|
||||
}
|
||||
|
||||
safe_undefined: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
unsafe: false,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
var a, c;
|
||||
console.log(function(undefined) {
|
||||
return function() {
|
||||
if (a)
|
||||
return b;
|
||||
if (c)
|
||||
return d;
|
||||
};
|
||||
}(1)());
|
||||
}
|
||||
expect: {
|
||||
var a, c;
|
||||
console.log(function(n) {
|
||||
return function() {
|
||||
return a ? b : c ? d : void 0;
|
||||
};
|
||||
}(1)());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_undefined: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
unsafe: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
var a, c;
|
||||
console.log(function(undefined) {
|
||||
return function() {
|
||||
if (a)
|
||||
return b;
|
||||
if (c)
|
||||
return d;
|
||||
};
|
||||
}()());
|
||||
}
|
||||
expect: {
|
||||
var a, c;
|
||||
console.log(function(n) {
|
||||
return function() {
|
||||
return a ? b : c ? d : n;
|
||||
};
|
||||
}()());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
runtime_error: {
|
||||
input: {
|
||||
const a = 1;
|
||||
console.log(a++);
|
||||
}
|
||||
expect: {
|
||||
const a = 1;
|
||||
console.log(a++);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
56
test/compress/issue-1609.js
Normal file
56
test/compress/issue-1609.js
Normal file
@@ -0,0 +1,56 @@
|
||||
chained_evaluation_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = 1;
|
||||
(function() {
|
||||
var b = a, c;
|
||||
c = f(b);
|
||||
c.bar = b;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function() {
|
||||
var c;
|
||||
c = f(1);
|
||||
c.bar = 1;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
chained_evaluation_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = "long piece of string";
|
||||
(function() {
|
||||
var b = a, c;
|
||||
c = f(b);
|
||||
c.bar = b;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a = "long piece of string";
|
||||
(function() {
|
||||
var c;
|
||||
c = f(a);
|
||||
c.bar = a;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ dead_code_const_annotation_regex: {
|
||||
var CONST_FOO_ANN = !1;
|
||||
if (CONST_FOO_ANN) console.log('reachable');
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
drop_console_2: {
|
||||
@@ -225,6 +226,7 @@ issue_1254_negate_iife_true: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_nested: {
|
||||
@@ -240,6 +242,7 @@ issue_1254_negate_iife_nested: {
|
||||
})()()()()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()()()()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
conditional: {
|
||||
|
||||
@@ -29,4 +29,5 @@ dont_mangle_arguments: {
|
||||
})(5,6,7);
|
||||
}
|
||||
expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ this_binding_conditionals: {
|
||||
this_binding_collapse_vars: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
};
|
||||
input: {
|
||||
var c = a; c();
|
||||
|
||||
@@ -42,6 +42,7 @@ eval_collapse_vars: {
|
||||
eval("console.log(a);");
|
||||
})(eval);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
eval_unused: {
|
||||
|
||||
@@ -9,6 +9,7 @@ labels_1: {
|
||||
expect: {
|
||||
foo || console.log("bar");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_2: {
|
||||
@@ -40,6 +41,7 @@ labels_3: {
|
||||
for (var i = 0; i < 5; ++i)
|
||||
i < 3 || console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_4: {
|
||||
@@ -54,6 +56,7 @@ labels_4: {
|
||||
for (var i = 0; i < 5; ++i)
|
||||
i < 3 || console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_5: {
|
||||
|
||||
@@ -166,6 +166,7 @@ keep_collapse_const_in_own_block_scope: {
|
||||
console.log(i);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
keep_collapse_const_in_own_block_scope_2: {
|
||||
@@ -186,6 +187,7 @@ keep_collapse_const_in_own_block_scope_2: {
|
||||
console.log(i);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
|
||||
@@ -70,6 +70,7 @@ negate_iife_3_evaluate: {
|
||||
expect: {
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_3_side_effects: {
|
||||
@@ -111,6 +112,7 @@ negate_iife_3_off_evaluate: {
|
||||
expect: {
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_4: {
|
||||
@@ -243,6 +245,7 @@ negate_iife_nested: {
|
||||
}(7);
|
||||
}).f();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_nested_off: {
|
||||
@@ -275,6 +278,7 @@ negate_iife_nested_off: {
|
||||
})(7);
|
||||
}).f();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_issue_1073: {
|
||||
@@ -299,6 +303,7 @@ negate_iife_issue_1073: {
|
||||
};
|
||||
}(7))();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_false: {
|
||||
@@ -313,6 +318,7 @@ issue_1254_negate_iife_false: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_true: {
|
||||
@@ -327,6 +333,7 @@ issue_1254_negate_iife_true: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '!function(){return function(){console.log("test")}}()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_nested: {
|
||||
@@ -341,6 +348,7 @@ issue_1254_negate_iife_nested: {
|
||||
})()()()()();
|
||||
}
|
||||
expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1288: {
|
||||
|
||||
@@ -58,6 +58,7 @@ reduce_vars: {
|
||||
})();
|
||||
console.log(2);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
modified: {
|
||||
@@ -166,7 +167,7 @@ modified: {
|
||||
console.log(A ? 'yes' : 'no');
|
||||
console.log(B ? 'yes' : 'no');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe_evaluate: {
|
||||
@@ -401,6 +402,7 @@ iife: {
|
||||
console.log(0, 1 * b, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_new: {
|
||||
@@ -420,6 +422,7 @@ iife_new: {
|
||||
console.log(0, 1 * b, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
multi_def: {
|
||||
@@ -707,6 +710,7 @@ toplevel_on: {
|
||||
expect: {
|
||||
console.log(3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_off: {
|
||||
@@ -724,6 +728,7 @@ toplevel_off: {
|
||||
var x = 3;
|
||||
console.log(x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_on_loops_1: {
|
||||
@@ -751,6 +756,7 @@ toplevel_on_loops_1: {
|
||||
})();
|
||||
while (x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_off_loops_1: {
|
||||
@@ -779,6 +785,7 @@ toplevel_off_loops_1: {
|
||||
bar();
|
||||
while (x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_on_loops_2: {
|
||||
@@ -1121,6 +1128,7 @@ defun_label: {
|
||||
}(2));
|
||||
}();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
double_reference: {
|
||||
@@ -1164,6 +1172,7 @@ iife_arguments_1: {
|
||||
return f;
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_arguments_2: {
|
||||
@@ -1186,6 +1195,7 @@ iife_arguments_2: {
|
||||
}() === arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_eval_1: {
|
||||
@@ -1207,6 +1217,7 @@ iife_eval_1: {
|
||||
return f;
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_eval_2: {
|
||||
@@ -1230,6 +1241,7 @@ iife_eval_2: {
|
||||
console.log(x() === eval("x"));
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_func_side_effects: {
|
||||
@@ -1326,4 +1338,29 @@ issue_1595_4: {
|
||||
if (a) iife(a - 1, b, c);
|
||||
})(3, 4, 5);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1606: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
hoist_vars: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var a;
|
||||
function g(){};
|
||||
var b = 2;
|
||||
x(b);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
var a, b;
|
||||
function g(){};
|
||||
b = 2;
|
||||
x(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
do_screw: {
|
||||
options = { screw_ie8: true };
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
beautify = {
|
||||
screw_ie8: true,
|
||||
ascii_only: true
|
||||
};
|
||||
|
||||
input: f("\v");
|
||||
expect_exact: 'f("\\v");';
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
f("\v");
|
||||
}
|
||||
expect_exact: 'f("\\v");'
|
||||
}
|
||||
|
||||
dont_screw: {
|
||||
options = { screw_ie8: false };
|
||||
beautify = { screw_ie8: false, ascii_only: true };
|
||||
|
||||
input: f("\v");
|
||||
expect_exact: 'f("\\x0B");';
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
beautify = {
|
||||
screw_ie8: false,
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
f("\v");
|
||||
}
|
||||
expect_exact: 'f("\\x0B");'
|
||||
}
|
||||
|
||||
do_screw_constants: {
|
||||
@@ -119,6 +128,7 @@ do_screw_try_catch_undefined: {
|
||||
return void 0===o
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dont_screw_try_catch_undefined: {
|
||||
@@ -147,6 +157,7 @@ dont_screw_try_catch_undefined: {
|
||||
return n === undefined
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
reduce_vars: {
|
||||
@@ -199,6 +210,7 @@ issue_1586_1: {
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1586_2: {
|
||||
@@ -217,4 +229,5 @@ issue_1586_2: {
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ make_sequences_4: {
|
||||
switch (x = 5, y) {}
|
||||
with (x = 5, obj);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
lift_sequences_1: {
|
||||
@@ -103,15 +104,18 @@ lift_sequences_1: {
|
||||
lift_sequences_2: {
|
||||
options = { sequences: true, evaluate: true };
|
||||
input: {
|
||||
var foo, bar;
|
||||
var foo = 1, bar;
|
||||
foo.x = (foo = {}, 10);
|
||||
bar = (bar = {}, 10);
|
||||
console.log(foo, bar);
|
||||
}
|
||||
expect: {
|
||||
var foo, bar;
|
||||
var foo = 1, bar;
|
||||
foo.x = (foo = {}, 10),
|
||||
bar = {}, bar = 10;
|
||||
bar = {}, bar = 10,
|
||||
console.log(foo, bar);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
lift_sequences_3: {
|
||||
@@ -138,6 +142,23 @@ lift_sequences_4: {
|
||||
}
|
||||
}
|
||||
|
||||
lift_sequences_5: {
|
||||
options = {
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a = 2, b;
|
||||
a *= (b, a = 4, 3);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 2, b;
|
||||
b, a *= (a = 4, 3),
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
for_sequences: {
|
||||
options = { sequences: true };
|
||||
input: {
|
||||
@@ -230,6 +251,7 @@ negate_iife_for: {
|
||||
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
|
||||
for (function() {}(); i < 5; i++) console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife: {
|
||||
|
||||
131
test/compress/transform.js
Normal file
131
test/compress/transform.js
Normal file
@@ -0,0 +1,131 @@
|
||||
booleans_evaluate: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof void 0 != "undefined");
|
||||
console.log(1 == 1, 1 === 1)
|
||||
console.log(1 != 1, 1 !== 1)
|
||||
}
|
||||
expect: {
|
||||
console.log(!1);
|
||||
console.log(!0, !0);
|
||||
console.log(!1, !1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
booleans_global_defs: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
global_defs: {
|
||||
A: true,
|
||||
},
|
||||
}
|
||||
input: {
|
||||
console.log(A == 1);
|
||||
}
|
||||
expect: {
|
||||
console.log(!0);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
condition_evaluate: {
|
||||
options = {
|
||||
booleans: true,
|
||||
dead_code: false,
|
||||
evaluate: true,
|
||||
loops: false,
|
||||
}
|
||||
input: {
|
||||
while (1 === 2);
|
||||
for (; 1 == true;);
|
||||
if (void 0 == null);
|
||||
}
|
||||
expect: {
|
||||
while (!1);
|
||||
for (; !0;);
|
||||
if (!0);
|
||||
}
|
||||
}
|
||||
|
||||
if_else_empty: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
if ({} ? a : b); else {}
|
||||
}
|
||||
expect: {
|
||||
!{} ? b : a;
|
||||
}
|
||||
}
|
||||
|
||||
label_if_break: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
L: if (true) {
|
||||
a;
|
||||
break L;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
a;
|
||||
}
|
||||
}
|
||||
|
||||
while_if_break: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
loops: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
while (a) {
|
||||
if (b) if(c) d;
|
||||
if (e) break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for(; a && (b && c && d, !e););
|
||||
}
|
||||
}
|
||||
|
||||
if_return: {
|
||||
options = {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(w, x, y, z) {
|
||||
if (x) return;
|
||||
if (w) {
|
||||
if (y) return;
|
||||
} else if (z) return;
|
||||
if (x == y) return true;
|
||||
|
||||
if (x) w();
|
||||
if (y) z();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(w, x, y, z) {
|
||||
if (!x) {
|
||||
if (w) {
|
||||
if (y) return;
|
||||
} else if (z) return;
|
||||
return x == y || (x && w(), y && z(), !0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ describe("bin/uglifyjs", function () {
|
||||
});
|
||||
});
|
||||
it("Should process inline source map", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-520/input.js -cm toplevel --in-source-map inline --source-map-inline';
|
||||
var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline';
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
@@ -78,6 +78,7 @@ describe("minify", function() {
|
||||
});
|
||||
it("Should process inline source map", function() {
|
||||
var code = Uglify.minify("./test/input/issue-520/input.js", {
|
||||
compress: { toplevel: true },
|
||||
inSourceMap: "inline",
|
||||
sourceMapInline: true
|
||||
}).code + "\n";
|
||||
|
||||
@@ -6,10 +6,22 @@ var U = require("../tools/node");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var assert = require("assert");
|
||||
var vm = require("vm");
|
||||
|
||||
var tests_dir = path.dirname(module.filename);
|
||||
var failures = 0;
|
||||
var failed_files = {};
|
||||
var same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
|
||||
if (typeof expected != typeof actual) return false;
|
||||
if (typeof expected != "string") {
|
||||
if (expected.name != actual.name) return false;
|
||||
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
|
||||
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
|
||||
}
|
||||
return expected == actual;
|
||||
} : function(expected, actual) {
|
||||
return typeof expected == typeof actual && expected.toString() == actual.toString();
|
||||
};
|
||||
|
||||
run_compress_tests();
|
||||
if (failures) {
|
||||
@@ -71,10 +83,15 @@ function test_directory(dir) {
|
||||
}
|
||||
|
||||
function as_toplevel(input, mangle_options) {
|
||||
if (input instanceof U.AST_BlockStatement) input = input.body;
|
||||
else if (input instanceof U.AST_Statement) input = [ input ];
|
||||
else throw new Error("Unsupported input syntax");
|
||||
var toplevel = new U.AST_Toplevel({ body: input });
|
||||
if (!(input instanceof U.AST_BlockStatement))
|
||||
throw new Error("Unsupported input syntax");
|
||||
for (var i = 0; i < input.body.length; i++) {
|
||||
var stat = input.body[i];
|
||||
if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String)
|
||||
input.body[i] = new U.AST_Directive(stat.body);
|
||||
else break;
|
||||
}
|
||||
var toplevel = new U.AST_Toplevel(input);
|
||||
toplevel.figure_out_scope(mangle_options);
|
||||
return toplevel;
|
||||
}
|
||||
@@ -165,6 +182,36 @@ function run_compress_tests() {
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
}
|
||||
if (test.expect_stdout) {
|
||||
var stdout = run_code(make_code(input, output_options));
|
||||
if (test.expect_stdout === true) {
|
||||
test.expect_stdout = stdout;
|
||||
}
|
||||
if (!same_stdout(test.expect_stdout, stdout)) {
|
||||
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_code,
|
||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: test.expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
} else {
|
||||
stdout = run_code(output);
|
||||
if (!same_stdout(test.expect_stdout, stdout)) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_code,
|
||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: test.expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var tests = parse_test(path.resolve(dir, file));
|
||||
@@ -215,9 +262,9 @@ function parse_test(file) {
|
||||
}
|
||||
|
||||
function read_string(stat) {
|
||||
if (stat.TYPE === "SimpleStatement") {
|
||||
if (stat.TYPE == "SimpleStatement") {
|
||||
var body = stat.body;
|
||||
out: switch(body.TYPE) {
|
||||
switch(body.TYPE) {
|
||||
case "String":
|
||||
return body.value;
|
||||
case "Array":
|
||||
@@ -243,23 +290,26 @@ function parse_test(file) {
|
||||
return true;
|
||||
}
|
||||
if (node instanceof U.AST_LabeledStatement) {
|
||||
var label = node.label;
|
||||
assert.ok(
|
||||
["input", "expect", "expect_exact", "expect_warnings"].indexOf(node.label.name) >= 0,
|
||||
["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0,
|
||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||
name: node.label.name,
|
||||
line: node.label.start.line,
|
||||
col: node.label.start.col
|
||||
name: label.name,
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
})
|
||||
);
|
||||
var stat = node.body;
|
||||
if (stat instanceof U.AST_BlockStatement) {
|
||||
if (stat.body.length == 1) stat = stat.body[0];
|
||||
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
||||
}
|
||||
if (node.label.name === "expect_exact") {
|
||||
test[node.label.name] = read_string(stat);
|
||||
if (label.name == "expect_exact") {
|
||||
test[label.name] = read_string(stat);
|
||||
} else if (label.name == "expect_stdout") {
|
||||
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
|
||||
test[label.name] = stat.body.value;
|
||||
} else {
|
||||
test[label.name] = read_string(stat) + "\n";
|
||||
}
|
||||
} else {
|
||||
test[node.label.name] = stat;
|
||||
test[label.name] = stat;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -281,3 +331,19 @@ function evaluate(code) {
|
||||
code = make_code(code, { beautify: true });
|
||||
return new Function("return(" + code + ")")();
|
||||
}
|
||||
|
||||
function run_code(code) {
|
||||
var stdout = "";
|
||||
var original_write = process.stdout.write;
|
||||
process.stdout.write = function(chunk) {
|
||||
stdout += chunk;
|
||||
};
|
||||
try {
|
||||
new vm.Script(code).runInNewContext({ console: console }, { timeout: 5000 });
|
||||
return stdout;
|
||||
} catch (ex) {
|
||||
return ex;
|
||||
} finally {
|
||||
process.stdout.write = original_write;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user