Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01d6e0f223 | ||
|
|
ab050e7a94 | ||
|
|
75aa6ef848 | ||
|
|
519a00bd8a | ||
|
|
3ff0feddee | ||
|
|
74396acc86 | ||
|
|
036bca980c | ||
|
|
18c2b1841b | ||
|
|
fe19ab7c57 | ||
|
|
9074f05129 | ||
|
|
04fbb1f949 | ||
|
|
bf7e4ca1a3 | ||
|
|
d68ddc31f9 | ||
|
|
500e31e03b | ||
|
|
bef856addb | ||
|
|
9a6faf365b | ||
|
|
e915832a36 | ||
|
|
0593892d6e |
271
lib/compress.js
271
lib/compress.js
@@ -648,7 +648,7 @@ merge(Compressor.prototype, {
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
if (has_break_or_continue(this)) {
|
||||
if (has_break_or_continue(this, tw.parent())) {
|
||||
pop(tw);
|
||||
push(tw);
|
||||
}
|
||||
@@ -665,7 +665,7 @@ merge(Compressor.prototype, {
|
||||
if (this.condition) this.condition.walk(tw);
|
||||
this.body.walk(tw);
|
||||
if (this.step) {
|
||||
if (has_break_or_continue(this)) {
|
||||
if (has_break_or_continue(this, tw.parent())) {
|
||||
pop(tw);
|
||||
push(tw);
|
||||
}
|
||||
@@ -701,8 +701,11 @@ merge(Compressor.prototype, {
|
||||
node.argnames.forEach(function(arg, i) {
|
||||
var d = arg.definition();
|
||||
if (d.fixed === undefined && (!node.uses_arguments || tw.has_directive("use strict"))) {
|
||||
var value = iife.args[i];
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
var j = node.argnames.indexOf(arg);
|
||||
if (j < 0) return value;
|
||||
return iife.args[j] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, true);
|
||||
@@ -1124,7 +1127,7 @@ merge(Compressor.prototype, {
|
||||
hit_index++;
|
||||
if (hit_index < hit_stack.length) return handle_custom_scan_order(node);
|
||||
hit = true;
|
||||
stop_after = find_stop(node, 0);
|
||||
stop_after = (value_def ? find_stop_value : find_stop)(node, 0);
|
||||
if (stop_after === node) abort = true;
|
||||
return node;
|
||||
}
|
||||
@@ -1147,7 +1150,7 @@ merge(Compressor.prototype, {
|
||||
&& (scan_lhs && lhs.equivalent_to(node)
|
||||
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
||||
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||
abort = true;
|
||||
if (!hit_rhs || !value_def) abort = true;
|
||||
return node;
|
||||
}
|
||||
if (is_lhs(node, parent)) {
|
||||
@@ -1540,12 +1543,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
function find_stop(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (parent instanceof AST_Array) return value_def ? find_stop(parent, level + 1) : node;
|
||||
if (parent instanceof AST_Array) return node;
|
||||
if (parent instanceof AST_Assign) return node;
|
||||
if (parent instanceof AST_Binary) {
|
||||
if (!value_def || parent.left !== node) return node;
|
||||
return find_stop(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Binary) return node;
|
||||
if (parent instanceof AST_Call) return node;
|
||||
if (parent instanceof AST_Case) return node;
|
||||
if (parent instanceof AST_Conditional) return node;
|
||||
@@ -1553,9 +1553,7 @@ merge(Compressor.prototype, {
|
||||
if (parent instanceof AST_Exit) return node;
|
||||
if (parent instanceof AST_If) return node;
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_ObjectKeyVal) {
|
||||
return value_def ? find_stop(scanner.parent(level + 1), level + 2) : node;
|
||||
}
|
||||
if (parent instanceof AST_ObjectKeyVal) return node;
|
||||
if (parent instanceof AST_PropAccess) return node;
|
||||
if (parent instanceof AST_Sequence) {
|
||||
return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
|
||||
@@ -1567,12 +1565,92 @@ merge(Compressor.prototype, {
|
||||
return null;
|
||||
}
|
||||
|
||||
function find_stop_value(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (parent instanceof AST_Array) return find_stop_value(parent, level + 1);
|
||||
if (parent instanceof AST_Assign) {
|
||||
if (may_throw(parent)) return node;
|
||||
if (parent.left instanceof AST_SymbolRef) {
|
||||
var name = parent.left.name;
|
||||
if (lhs.name == name) return node;
|
||||
if (value_def.name == name) return node;
|
||||
}
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Binary) {
|
||||
if (lazy_op[parent.operator] && parent.left !== node) {
|
||||
do {
|
||||
node = parent;
|
||||
parent = scanner.parent(++level);
|
||||
} while (parent instanceof AST_Binary && parent.operator == node.operator);
|
||||
return node;
|
||||
}
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Call) return parent;
|
||||
if (parent instanceof AST_Case) {
|
||||
if (parent.expression !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Conditional) {
|
||||
if (parent.condition !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Do) return node;
|
||||
if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_For) {
|
||||
if (parent.init !== node && parent.condition !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_ForIn) {
|
||||
if (parent.init !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_If) {
|
||||
if (parent.condition !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_ObjectKeyVal) {
|
||||
var obj = scanner.parent(level + 1);
|
||||
return all(obj.properties, function(prop) {
|
||||
return prop instanceof AST_ObjectKeyVal;
|
||||
}) ? find_stop_value(obj, level + 2) : obj;
|
||||
}
|
||||
if (parent instanceof AST_PropAccess) return find_stop_value(parent, level + 1);
|
||||
if (parent instanceof AST_Sequence) {
|
||||
return (parent.tail_node() === node ? find_stop_value : find_stop_unused)(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Switch) {
|
||||
if (parent.expression !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Unary) {
|
||||
if (parent.operator == "delete") return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_VarDef) {
|
||||
var name = parent.name.name;
|
||||
if (lhs.name == name) return node;
|
||||
if (value_def.name == name) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_While) {
|
||||
if (parent.condition !== node) return node;
|
||||
return find_stop_value(parent, level + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function find_stop_unused(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (is_last_node(node, parent)) return node;
|
||||
if (in_conditional(node, parent)) return node;
|
||||
if (parent instanceof AST_Array) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Assign) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Assign) {
|
||||
return may_throw(parent) ? node : find_stop_unused(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_Binary) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Call) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Case) return find_stop_unused(parent, level + 1);
|
||||
@@ -1581,7 +1659,12 @@ merge(Compressor.prototype, {
|
||||
if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_If) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_ObjectKeyVal) return find_stop_unused(scanner.parent(level + 1), level + 2);
|
||||
if (parent instanceof AST_ObjectKeyVal) {
|
||||
var obj = scanner.parent(level + 1);
|
||||
return all(obj.properties, function(prop) {
|
||||
return prop instanceof AST_ObjectKeyVal;
|
||||
}) ? find_stop_unused(obj, level + 2) : obj;
|
||||
}
|
||||
if (parent instanceof AST_PropAccess) {
|
||||
var exp = parent.expression;
|
||||
if (exp === node) return find_stop_unused(parent, level + 1);
|
||||
@@ -4638,8 +4721,11 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
function if_break_in_loop(self, compressor) {
|
||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
||||
if (compressor.option("dead_code") && is_break(first)) {
|
||||
var first = first_statement(self.body);
|
||||
if (compressor.option("dead_code")
|
||||
&& (first instanceof AST_Break
|
||||
|| first instanceof AST_Continue && external_target(first)
|
||||
|| first instanceof AST_Exit)) {
|
||||
var body = [];
|
||||
if (self.init instanceof AST_Statement) {
|
||||
body.push(self.init);
|
||||
@@ -4648,10 +4734,19 @@ merge(Compressor.prototype, {
|
||||
body: self.init
|
||||
}));
|
||||
}
|
||||
if (self.condition) {
|
||||
var retain = external_target(first) || first instanceof AST_Exit;
|
||||
if (self.condition && retain) {
|
||||
body.push(make_node(AST_If, self, {
|
||||
condition: self.condition,
|
||||
body: first,
|
||||
alternative: null
|
||||
}));
|
||||
} else if (self.condition) {
|
||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
||||
body: self.condition
|
||||
}));
|
||||
} else if (retain) {
|
||||
body.push(first);
|
||||
}
|
||||
extract_declarations_from_unreachable_code(self.body, body);
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
@@ -4659,7 +4754,8 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
if (first instanceof AST_If) {
|
||||
if (is_break(first.body)) {
|
||||
var ab = first_statement(first.body);
|
||||
if (ab instanceof AST_Break && !external_target(ab)) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -4669,8 +4765,12 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
self.condition = first.condition.negate(compressor);
|
||||
}
|
||||
drop_it(first.alternative);
|
||||
} else if (is_break(first.alternative)) {
|
||||
var body = as_statement_array(first.alternative);
|
||||
extract_declarations_from_unreachable_code(first.body, body);
|
||||
return drop_it(body);
|
||||
}
|
||||
ab = first_statement(first.alternative);
|
||||
if (ab instanceof AST_Break && !external_target(ab)) {
|
||||
if (self.condition) {
|
||||
self.condition = make_node(AST_Binary, self.condition, {
|
||||
left: self.condition,
|
||||
@@ -4680,18 +4780,22 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
self.condition = first.condition;
|
||||
}
|
||||
drop_it(first.body);
|
||||
var body = as_statement_array(first.body);
|
||||
extract_declarations_from_unreachable_code(first.alternative, body);
|
||||
return drop_it(body);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
|
||||
function is_break(node) {
|
||||
return node instanceof AST_Break
|
||||
&& compressor.loopcontrol_target(node) === compressor.self();
|
||||
function first_statement(body) {
|
||||
return body instanceof AST_BlockStatement ? body.body[0] : body;
|
||||
}
|
||||
|
||||
function external_target(node) {
|
||||
return compressor.loopcontrol_target(node) !== compressor.self();
|
||||
}
|
||||
|
||||
function drop_it(rest) {
|
||||
rest = as_statement_array(rest);
|
||||
if (self.body instanceof AST_BlockStatement) {
|
||||
self.body = self.body.clone();
|
||||
self.body.body = rest.concat(self.body.body.slice(1));
|
||||
@@ -4701,7 +4805,7 @@ merge(Compressor.prototype, {
|
||||
body: rest
|
||||
}).transform(compressor);
|
||||
}
|
||||
self = if_break_in_loop(self, compressor);
|
||||
return if_break_in_loop(self, compressor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5157,24 +5261,52 @@ merge(Compressor.prototype, {
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.pinned()) {
|
||||
var pos = 0, last = 0;
|
||||
var drop_fargs = exp === fn && !fn.name && compressor.drop_fargs(fn, self);
|
||||
var side_effects = [];
|
||||
for (var i = 0; i < self.args.length; i++) {
|
||||
var trim = i >= fn.argnames.length;
|
||||
if (trim || fn.argnames[i].__unused) {
|
||||
var node = self.args[i].drop_side_effect_free(compressor);
|
||||
if (node) {
|
||||
self.args[pos++] = node;
|
||||
if (drop_fargs) {
|
||||
fn.argnames.splice(i, 1);
|
||||
self.args.splice(i, 1);
|
||||
if (node) side_effects.push(node);
|
||||
i--;
|
||||
continue;
|
||||
} else if (node) {
|
||||
side_effects.push(node);
|
||||
self.args[pos++] = make_sequence(self, side_effects);
|
||||
side_effects = [];
|
||||
} else if (!trim) {
|
||||
self.args[pos++] = make_node(AST_Number, self.args[i], {
|
||||
value: 0
|
||||
});
|
||||
if (side_effects.length) {
|
||||
node = make_sequence(self, side_effects);
|
||||
side_effects = [];
|
||||
} else {
|
||||
node = make_node(AST_Number, self.args[i], {
|
||||
value: 0
|
||||
});
|
||||
}
|
||||
self.args[pos++] = node;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
self.args[pos++] = self.args[i];
|
||||
side_effects.push(self.args[i]);
|
||||
self.args[pos++] = make_sequence(self, side_effects);
|
||||
side_effects = [];
|
||||
}
|
||||
last = pos;
|
||||
}
|
||||
if (drop_fargs) for (; i < fn.argnames.length; i++) {
|
||||
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
|
||||
}
|
||||
self.args.length = last;
|
||||
if (side_effects.length) {
|
||||
var arg = make_sequence(self, side_effects);
|
||||
self.args.push(self.args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, self, {
|
||||
operator: "void",
|
||||
expression: arg
|
||||
}) : arg);
|
||||
}
|
||||
}
|
||||
if (compressor.option("unsafe")) {
|
||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||
@@ -6534,6 +6666,7 @@ merge(Compressor.prototype, {
|
||||
name.scope = value;
|
||||
value.name = name;
|
||||
lambda_def = value.def_function(name);
|
||||
lambda_def.recursive_refs = def.recursive_refs;
|
||||
}
|
||||
value.walk(new TreeWalker(function(node) {
|
||||
if (!(node instanceof AST_SymbolRef)) return;
|
||||
@@ -6872,25 +7005,42 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
// x ? y(a) : y(b) --> y(x ? a : b)
|
||||
var arg_index;
|
||||
// x ? y : y --> x, y
|
||||
if (consequent.equivalent_to(alternative)) return make_sequence(self, [
|
||||
condition,
|
||||
consequent
|
||||
]).optimize(compressor);
|
||||
if (consequent instanceof AST_Call
|
||||
&& alternative.TYPE === consequent.TYPE
|
||||
&& consequent.args.length > 0
|
||||
&& consequent.args.length == alternative.args.length
|
||||
&& consequent.expression.equivalent_to(alternative.expression)
|
||||
&& !condition.has_side_effects(compressor)
|
||||
&& !consequent.expression.has_side_effects(compressor)
|
||||
&& typeof (arg_index = single_arg_diff()) == "number") {
|
||||
var node = consequent.clone();
|
||||
node.args[arg_index] = make_node(AST_Conditional, self, {
|
||||
condition: condition,
|
||||
consequent: consequent.args[arg_index],
|
||||
alternative: alternative.args[arg_index]
|
||||
});
|
||||
return node;
|
||||
&& consequent.args.length == alternative.args.length) {
|
||||
var arg_index = arg_diff();
|
||||
// x ? y(a) : z(a) --> (x ? y : z)(a)
|
||||
if (arg_index == -1
|
||||
&& !(consequent.expression instanceof AST_PropAccess)
|
||||
&& !(alternative.expression instanceof AST_PropAccess)) {
|
||||
var node = consequent.clone();
|
||||
node.expression = make_node(AST_Conditional, self, {
|
||||
condition: condition,
|
||||
consequent: consequent.expression,
|
||||
alternative: alternative.expression
|
||||
});
|
||||
return node;
|
||||
}
|
||||
// x ? y(a) : y(b) --> y(x ? a : b)
|
||||
if (arg_index >= 0
|
||||
&& consequent.expression.equivalent_to(alternative.expression)
|
||||
&& !condition.has_side_effects(compressor)
|
||||
&& !consequent.expression.has_side_effects(compressor)) {
|
||||
var node = consequent.clone();
|
||||
node.args[arg_index] = make_node(AST_Conditional, self, {
|
||||
condition: condition,
|
||||
consequent: consequent.args[arg_index],
|
||||
alternative: alternative.args[arg_index]
|
||||
});
|
||||
return node;
|
||||
}
|
||||
}
|
||||
// x?y?z:a:a --> x&&y?z:a
|
||||
// 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, {
|
||||
@@ -6903,12 +7053,18 @@ merge(Compressor.prototype, {
|
||||
alternative: alternative
|
||||
});
|
||||
}
|
||||
// x ? y : y --> x, y
|
||||
if (consequent.equivalent_to(alternative)) {
|
||||
return make_sequence(self, [
|
||||
condition,
|
||||
consequent
|
||||
]).optimize(compressor);
|
||||
// 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, {
|
||||
condition: make_node(AST_Binary, self, {
|
||||
left: condition,
|
||||
operator: "||",
|
||||
right: alternative.condition
|
||||
}),
|
||||
consequent: consequent,
|
||||
alternative: alternative.alternative
|
||||
});
|
||||
}
|
||||
// x ? (y, w) : (z, w) --> x ? y : z, w
|
||||
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
|
||||
@@ -7012,17 +7168,18 @@ merge(Compressor.prototype, {
|
||||
&& node.expression.getValue());
|
||||
}
|
||||
|
||||
function single_arg_diff() {
|
||||
function arg_diff() {
|
||||
var a = consequent.args;
|
||||
var b = alternative.args;
|
||||
for (var i = 0, len = a.length; i < len; i++) {
|
||||
if (!a[i].equivalent_to(b[i])) {
|
||||
for (var j = i + 1; j < len; j++) {
|
||||
if (!a[j].equivalent_to(b[j])) return;
|
||||
if (!a[j].equivalent_to(b[j])) return -2;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function can_shift_lhs_of_tail(node) {
|
||||
|
||||
119
lib/output.js
119
lib/output.js
@@ -43,8 +43,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
||||
|
||||
function is_some_comments(comment) {
|
||||
// multiline comment
|
||||
return comment.type == "comment2" && /@preserve|@license|@cc_on/i.test(comment.value);
|
||||
@@ -269,7 +267,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
newline_insert = -1;
|
||||
var prev = last.charAt(last.length - 1);
|
||||
var prev = last.slice(-1);
|
||||
if (might_need_semicolon) {
|
||||
might_need_semicolon = false;
|
||||
|
||||
@@ -298,16 +296,16 @@ function OutputStream(options) {
|
||||
}
|
||||
|
||||
if (might_need_space) {
|
||||
if ((is_identifier_char(prev)
|
||||
&& (is_identifier_char(ch) || ch == "\\"))
|
||||
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|
||||
|| (ch == "/" && ch == prev)
|
||||
|| ((ch == "+" || ch == "-") && ch == last))
|
||||
{
|
||||
|| ((ch == "+" || ch == "-") && ch == last)
|
||||
|| str == "--" && last == "!"
|
||||
|| last == "--" && ch == ">") {
|
||||
OUTPUT += " ";
|
||||
current_col++;
|
||||
current_pos++;
|
||||
}
|
||||
might_need_space = false;
|
||||
if (prev != "<" || str != "!") might_need_space = false;
|
||||
}
|
||||
|
||||
if (mapping_token) {
|
||||
@@ -322,7 +320,7 @@ function OutputStream(options) {
|
||||
}
|
||||
|
||||
OUTPUT += str;
|
||||
has_parens = str[str.length - 1] == "(";
|
||||
has_parens = str.slice(-1) == "(";
|
||||
current_pos += str.length;
|
||||
var a = str.split(/\r?\n/), n = a.length - 1;
|
||||
current_line += n;
|
||||
@@ -378,7 +376,7 @@ function OutputStream(options) {
|
||||
};
|
||||
|
||||
function force_semicolon() {
|
||||
might_need_semicolon = false;
|
||||
if (might_need_semicolon) print(";");
|
||||
print(";");
|
||||
}
|
||||
|
||||
@@ -585,17 +583,7 @@ function OutputStream(options) {
|
||||
force_semicolon : force_semicolon,
|
||||
to_utf8 : to_utf8,
|
||||
print_name : function(name) { print(make_name(name)) },
|
||||
print_string : function(str, quote, escape_directive) {
|
||||
var encoded = encode_string(str, quote);
|
||||
if (escape_directive === true && encoded.indexOf("\\") === -1) {
|
||||
// Insert semicolons to break directive prologue
|
||||
if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
|
||||
force_semicolon();
|
||||
}
|
||||
force_semicolon();
|
||||
}
|
||||
print(encoded);
|
||||
},
|
||||
print_string : function(str, quote) { print(encode_string(str, quote)) },
|
||||
next_indent : next_indent,
|
||||
with_indent : with_indent,
|
||||
with_block : with_block,
|
||||
@@ -633,17 +621,10 @@ function OutputStream(options) {
|
||||
nodetype.DEFMETHOD("_codegen", generator);
|
||||
}
|
||||
|
||||
var in_directive = false;
|
||||
var active_scope = null;
|
||||
var use_asm = null;
|
||||
var use_asm = false;
|
||||
|
||||
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||
var self = this, generator = self._codegen;
|
||||
if (self instanceof AST_Scope) {
|
||||
active_scope = self;
|
||||
} else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||
use_asm = active_scope;
|
||||
}
|
||||
function doit() {
|
||||
stream.prepend_comments(self);
|
||||
self.add_source_map(stream);
|
||||
@@ -657,9 +638,6 @@ function OutputStream(options) {
|
||||
doit();
|
||||
}
|
||||
stream.pop_node();
|
||||
if (self === use_asm) {
|
||||
use_asm = null;
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
|
||||
@@ -828,7 +806,18 @@ function OutputStream(options) {
|
||||
/* -----[ PRINTERS ]----- */
|
||||
|
||||
DEFPRINT(AST_Directive, function(self, output) {
|
||||
output.print_string(self.value, self.quote);
|
||||
var quote = self.quote;
|
||||
var value = self.value;
|
||||
switch (output.option("quote_style")) {
|
||||
case 0:
|
||||
case 2:
|
||||
if (value.indexOf('"') == -1) quote = '"';
|
||||
break;
|
||||
case 1:
|
||||
if (value.indexOf("'") == -1) quote = "'";
|
||||
break;
|
||||
}
|
||||
output.print(quote + value + quote);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Debugger, function(self, output) {
|
||||
@@ -840,30 +829,27 @@ function OutputStream(options) {
|
||||
|
||||
function display_body(body, is_toplevel, output, allow_directives) {
|
||||
var last = body.length - 1;
|
||||
in_directive = allow_directives;
|
||||
var in_directive = allow_directives;
|
||||
var was_asm = use_asm;
|
||||
body.forEach(function(stmt, i) {
|
||||
if (in_directive === true && !(stmt instanceof AST_Directive ||
|
||||
stmt instanceof AST_EmptyStatement ||
|
||||
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
|
||||
)) {
|
||||
in_directive = false;
|
||||
}
|
||||
if (!(stmt instanceof AST_EmptyStatement)) {
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
if (!(i == last && is_toplevel)) {
|
||||
output.newline();
|
||||
if (is_toplevel) output.newline();
|
||||
if (in_directive) {
|
||||
if (stmt instanceof AST_Directive) {
|
||||
if (stmt.value == "use asm") use_asm = true;
|
||||
} else if (!(stmt instanceof AST_EmptyStatement)) {
|
||||
if (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String) {
|
||||
output.force_semicolon();
|
||||
}
|
||||
in_directive = false;
|
||||
}
|
||||
}
|
||||
if (in_directive === true &&
|
||||
stmt instanceof AST_SimpleStatement &&
|
||||
stmt.body instanceof AST_String
|
||||
) {
|
||||
in_directive = false;
|
||||
}
|
||||
if (stmt instanceof AST_EmptyStatement) return;
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
if (i == last && is_toplevel) return;
|
||||
output.newline();
|
||||
if (is_toplevel) output.newline();
|
||||
});
|
||||
in_directive = false;
|
||||
use_asm = was_asm;
|
||||
}
|
||||
|
||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
|
||||
@@ -1254,29 +1240,10 @@ function OutputStream(options) {
|
||||
output.print(self.operator);
|
||||
});
|
||||
DEFPRINT(AST_Binary, function(self, output) {
|
||||
var op = self.operator;
|
||||
self.left.print(output);
|
||||
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
|
||||
&& self.left instanceof AST_UnaryPostfix
|
||||
&& self.left.operator == "--") {
|
||||
// space is mandatory to avoid outputting -->
|
||||
output.print(" ");
|
||||
} else {
|
||||
// the space is optional depending on "beautify"
|
||||
output.space();
|
||||
}
|
||||
output.print(op);
|
||||
if ((op == "<" || op == "<<")
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
&& self.right.operator == "!"
|
||||
&& self.right.expression instanceof AST_UnaryPrefix
|
||||
&& self.right.expression.operator == "--") {
|
||||
// space is mandatory to avoid outputting <!--
|
||||
output.print(" ");
|
||||
} else {
|
||||
// the space is optional depending on "beautify"
|
||||
output.space();
|
||||
}
|
||||
output.space();
|
||||
output.print(self.operator);
|
||||
output.space();
|
||||
self.right.print(output);
|
||||
});
|
||||
DEFPRINT(AST_Conditional, function(self, output) {
|
||||
@@ -1367,7 +1334,7 @@ function OutputStream(options) {
|
||||
output.print(self.getValue());
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output) {
|
||||
output.print_string(self.getValue(), self.quote, in_directive);
|
||||
output.print_string(self.getValue(), self.quote);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output) {
|
||||
if (use_asm && self.start && self.start.raw != null) {
|
||||
|
||||
@@ -790,9 +790,10 @@ function parse($TEXT, options) {
|
||||
var dir = S.in_directives;
|
||||
var body = expression(true);
|
||||
if (dir) {
|
||||
var token = body.start;
|
||||
if (body instanceof AST_String && token.raw.indexOf("\\") == -1) {
|
||||
S.input.add_directive(token.value);
|
||||
if (body instanceof AST_String) {
|
||||
var value = body.start.raw.slice(1, -1);
|
||||
S.input.add_directive(value);
|
||||
body.value = value;
|
||||
} else {
|
||||
S.in_directives = dir = false;
|
||||
}
|
||||
|
||||
@@ -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.1",
|
||||
"version": "3.7.3",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -1047,12 +1047,11 @@ collapse_vars_repeated: {
|
||||
var a = 3, a = x;
|
||||
return a;
|
||||
}
|
||||
(function(x){
|
||||
(function(x) {
|
||||
var a = "GOOD" + x, e = "BAD", k = "!", e = a;
|
||||
console.log(e + k);
|
||||
})("!"),
|
||||
|
||||
(function(x){
|
||||
(function(x) {
|
||||
var a = "GOOD" + x, e = "BAD" + x, k = "!", e = a;
|
||||
console.log(e + k);
|
||||
})("!");
|
||||
@@ -1064,10 +1063,10 @@ collapse_vars_repeated: {
|
||||
function f2(x) {
|
||||
return x;
|
||||
}
|
||||
(function(x){
|
||||
(function(x) {
|
||||
console.log("GOOD!!");
|
||||
})(),
|
||||
(function(x){
|
||||
(function(x) {
|
||||
console.log("GOOD!!");
|
||||
})();
|
||||
}
|
||||
@@ -2579,6 +2578,23 @@ chained_3: {
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
chained_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo", b = 42;
|
||||
var b = void (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo", b = 42;
|
||||
var b = void (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo undefined"
|
||||
}
|
||||
|
||||
boolean_binary_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -4566,8 +4582,8 @@ replace_all_var_scope: {
|
||||
var a = 100, b = 10;
|
||||
(function(r, a) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case a++:
|
||||
case (b += a):
|
||||
case a++:
|
||||
}
|
||||
})(--b, a);
|
||||
console.log(a, b);
|
||||
@@ -4576,8 +4592,8 @@ replace_all_var_scope: {
|
||||
var a = 100, b = 10;
|
||||
(function(c, o) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case o++:
|
||||
case (b += a):
|
||||
case o++:
|
||||
}
|
||||
})(--b, a);
|
||||
console.log(a, b);
|
||||
@@ -6965,3 +6981,444 @@ setter_side_effect: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
substitution_assign: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
f1 = b = a;
|
||||
console.log(a, b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
a = 1 + (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
b = 1 + (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
f1 = a;
|
||||
console.log(a, a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
a = 1 + (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
b = 1 + (b = a);
|
||||
console.log(a, b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect_stdout: [
|
||||
"42 42",
|
||||
"43 42",
|
||||
"42 43",
|
||||
]
|
||||
}
|
||||
|
||||
substitution_arithmetic: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log((b = a) + a, b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a - (b = a), b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a / (b = a) + b, b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(a + a, a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a - a, a);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a / a + a, a);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect_stdout: [
|
||||
"84 42",
|
||||
"0 42",
|
||||
"43 42",
|
||||
]
|
||||
}
|
||||
|
||||
substitution_logical_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log((b = a) && a, b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a && (b = a), b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(a && a, a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a && (b = a), b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"42 42",
|
||||
"null null",
|
||||
"42 42",
|
||||
"null true"
|
||||
]
|
||||
}
|
||||
|
||||
substitution_logical_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log((b = a) && a && b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log((b = a) && a || b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log((b = a) || a && b);
|
||||
}
|
||||
function f4(a, b) {
|
||||
console.log((b = a) || a || b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
f3(42, "foo");
|
||||
f3(null, true);
|
||||
f4(42, "foo");
|
||||
f4(null, true);
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(a && a && a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a && a || a);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a || a && a);
|
||||
}
|
||||
function f4(a, b) {
|
||||
console.log(a || a || a);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
f3(42, "foo");
|
||||
f3(null, true);
|
||||
f4(42, "foo");
|
||||
f4(null, true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"42",
|
||||
"null",
|
||||
"42",
|
||||
"null",
|
||||
"42",
|
||||
"null",
|
||||
"42",
|
||||
"null",
|
||||
]
|
||||
}
|
||||
|
||||
substitution_logical_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log(a && (b = a) && b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a && (b = a) || b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a || (b = a) && b);
|
||||
}
|
||||
function f4(a, b) {
|
||||
console.log(a || (b = a) || b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
f3(42, "foo");
|
||||
f3(null, true);
|
||||
f4(42, "foo");
|
||||
f4(null, true);
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(a && a && a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a && (b = a) || b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a || a && a);
|
||||
}
|
||||
function f4(a, b) {
|
||||
console.log(a || a || a);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f1(null, true);
|
||||
f2(42, "foo");
|
||||
f2(null, true);
|
||||
f3(42, "foo");
|
||||
f3(null, true);
|
||||
f4(42, "foo");
|
||||
f4(null, true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"42",
|
||||
"null",
|
||||
"42",
|
||||
"true",
|
||||
"42",
|
||||
"null",
|
||||
"42",
|
||||
"null",
|
||||
]
|
||||
}
|
||||
|
||||
substitution_conditional: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log((b = a) ? a : b, a, b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a ? b = a : b, a, b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a ? a : b = a, a, b);
|
||||
}
|
||||
f1("foo", "bar");
|
||||
f1(null, true);
|
||||
f2("foo", "bar");
|
||||
f2(null, true);
|
||||
f3("foo", "bar");
|
||||
f3(null, true);
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(a ? a : a, a, a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(a ? b = a : b, a, b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(a ? a : b = a, a, b);
|
||||
}
|
||||
f1("foo", "bar");
|
||||
f1(null, true);
|
||||
f2("foo", "bar");
|
||||
f2(null, true);
|
||||
f3("foo", "bar");
|
||||
f3(null, true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo foo foo",
|
||||
"null null null",
|
||||
"foo foo foo",
|
||||
"true null true",
|
||||
"foo foo bar",
|
||||
"null null null",
|
||||
]
|
||||
}
|
||||
|
||||
substitution_unary: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, b) {
|
||||
console.log(typeof (b = a), a, b);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(void (b = a), a, b);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(delete (b = a), a, b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f1(a, b) {
|
||||
console.log(typeof a, a, a);
|
||||
}
|
||||
function f2(a, b) {
|
||||
console.log(void a, a, a);
|
||||
}
|
||||
function f3(a, b) {
|
||||
console.log(delete (b = a), a, b);
|
||||
}
|
||||
f1(42, "foo");
|
||||
f2(42, "foo");
|
||||
f3(42, "foo");
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 42 42",
|
||||
"undefined 42 42",
|
||||
"true 42 42",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3626_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo", b = 42;
|
||||
a.p && (b = a) && a;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo", b = 42;
|
||||
a.p && (b = a) && a;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo 42"
|
||||
}
|
||||
|
||||
issue_3626_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo", b = 42, c = null;
|
||||
if (a && a.p)
|
||||
if (b = a)
|
||||
c++ + a;
|
||||
console.log(a, b, c);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo", b = 42, c = null;
|
||||
a && a.p && (b = a) && c++ + a;
|
||||
console.log(a, b, c);
|
||||
}
|
||||
expect_stdout: "foo 42 null"
|
||||
}
|
||||
|
||||
issue_3628_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "bar", b;
|
||||
({
|
||||
get p() {
|
||||
a = "foo";
|
||||
},
|
||||
q: b = a
|
||||
}).p;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "bar", b;
|
||||
({
|
||||
get p() {
|
||||
a = "foo";
|
||||
},
|
||||
q: b = a
|
||||
}).p;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo bar"
|
||||
}
|
||||
|
||||
issue_3628_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "bar", b;
|
||||
({
|
||||
get p() {
|
||||
a = "foo";
|
||||
},
|
||||
q: (b = a, 42)
|
||||
}).p;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "bar", b;
|
||||
({
|
||||
get p() {
|
||||
a = "foo";
|
||||
},
|
||||
q: (b = a, 42)
|
||||
}).p;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo bar"
|
||||
}
|
||||
|
||||
issue_3641: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
try {
|
||||
a = "foo";
|
||||
b = (a += (A.p = 0, "bar")) % 0;
|
||||
} catch (e) {}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
try {
|
||||
a = "foo";
|
||||
b = (a += (A.p = 0, "bar")) % 0;
|
||||
} catch (e) {}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "foo undefined"
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ unsafe_comps: {
|
||||
}
|
||||
expect: {
|
||||
var obj1, obj2;
|
||||
obj2 < obj1 ? g1() : f1();
|
||||
obj1 < obj2 ? f2() : g2();
|
||||
obj1 < obj2 ? g3() : f3();
|
||||
obj2 < obj1 ? f4() : g4();
|
||||
(obj2 < obj1 ? g1 : f1)();
|
||||
(obj1 < obj2 ? f2 : g2)();
|
||||
(obj1 < obj2 ? g3 : f3)();
|
||||
(obj2 < obj1 ? f4 : g4)();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ ifs_2: {
|
||||
}
|
||||
expect: {
|
||||
foo ? x() : bar ? y() : baz && z();
|
||||
foo ? x() : bar ? y() : baz ? z() : t();
|
||||
(foo ? x : bar ? y : baz ? z : t)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ cond_5: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
some_condition() && some_other_condition() ? do_something() : alternate();
|
||||
(some_condition() && some_other_condition() ? do_something : alternate)();
|
||||
some_condition() && some_other_condition() && do_something();
|
||||
}
|
||||
}
|
||||
@@ -663,6 +663,69 @@ cond_9: {
|
||||
}
|
||||
}
|
||||
|
||||
cond_10: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
if (1 == a) return "foo";
|
||||
if (2 == a) return "foo";
|
||||
if (3 == a) return "foo";
|
||||
if (4 == a) return 42;
|
||||
if (5 == a) return "foo";
|
||||
if (6 == a) return "foo";
|
||||
return "bar";
|
||||
}
|
||||
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
return 1 == a || 2 == a || 3 == a ? "foo" : 4 == a ? 42 : 5 == a || 6 == a ? "foo" : "bar";
|
||||
}
|
||||
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
|
||||
}
|
||||
expect_stdout: "foo foo foo 42 foo foo bar"
|
||||
}
|
||||
|
||||
cond_11: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
p: "foo",
|
||||
q: function() {
|
||||
return this.p;
|
||||
}
|
||||
};
|
||||
function f() {
|
||||
return "bar";
|
||||
}
|
||||
function g(a) {
|
||||
return a ? f() : o.q();
|
||||
}
|
||||
console.log(g(0), g(1));
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: "foo",
|
||||
q: function() {
|
||||
return this.p;
|
||||
}
|
||||
};
|
||||
function f() {
|
||||
return "bar";
|
||||
}
|
||||
function g(a) {
|
||||
return a ? f() : o.q();
|
||||
}
|
||||
console.log(g(0), g(1));
|
||||
}
|
||||
expect_stdout: "foo bar"
|
||||
}
|
||||
|
||||
ternary_boolean_consequent: {
|
||||
options = {
|
||||
booleans: true,
|
||||
|
||||
@@ -93,3 +93,41 @@ issue_3166: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valid_after_invalid_1: {
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
"use\x20strict";
|
||||
"use strict";
|
||||
return this;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
"use\x20strict";
|
||||
"use strict";
|
||||
return this;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
valid_after_invalid_2: {
|
||||
options = {
|
||||
directives: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
"use\x20strict";
|
||||
"use strict";
|
||||
return this;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
return this;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -1,55 +1,107 @@
|
||||
html_comment_in_expression: {
|
||||
input: {
|
||||
function f(a, b, x, y) { return a < !--b && x-- > y; }
|
||||
(function(a, b) {
|
||||
console.log(a < !--b && a-- > b, a, b);
|
||||
})(1, 2);
|
||||
}
|
||||
expect_exact: "function f(a,b,x,y){return a< !--b&&x-- >y}";
|
||||
expect_exact: "(function(a,b){console.log(a<! --b&&a-- >b,a,b)})(1,2);"
|
||||
expect_stdout: "false 1 1"
|
||||
}
|
||||
|
||||
html_comment_in_less_than: {
|
||||
input: {
|
||||
function f(a, b) { return a < !--b; }
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a < !--b,
|
||||
a < !--b + c,
|
||||
a + b < !--c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "function f(a,b){return a< !--b}";
|
||||
expect_exact: "(function(a,b,c){console.log(a<! --b,a<! --b+c,a+b<! --c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "false true false 1 0 2"
|
||||
}
|
||||
|
||||
html_comment_in_left_shift: {
|
||||
input: {
|
||||
function f(a, b) { return a << !--b; }
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a << !--b,
|
||||
a << !--b + c,
|
||||
a + b << !--c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "function f(a,b){return a<< !--b}";
|
||||
}
|
||||
|
||||
html_comment_in_right_shift: {
|
||||
input: {
|
||||
function f(a, b) { return a-- >> b; }
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >>b}";
|
||||
}
|
||||
|
||||
html_comment_in_zero_fill_right_shift: {
|
||||
input: {
|
||||
function f(a, b) { return a-- >>> b; }
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >>>b}";
|
||||
expect_exact: "(function(a,b,c){console.log(a<<! --b,a<<! --b+c,a+b<<! --c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "1 16 1 1 0 2"
|
||||
}
|
||||
|
||||
html_comment_in_greater_than: {
|
||||
input: {
|
||||
function f(a, b) { return a-- > b; }
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a-- > b,
|
||||
a-- > b + c,
|
||||
a + b-- > c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >b}";
|
||||
expect_exact: "(function(a,b,c){console.log(a-- >b,a-- >b+c,a+b-- >c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "false false false -1 1 3"
|
||||
}
|
||||
|
||||
html_comment_in_greater_than_or_equal: {
|
||||
input: {
|
||||
function f(a, b) { return a-- >= b; }
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a-- >= b,
|
||||
a-- >= b + c,
|
||||
a + b-- >= c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >=b}";
|
||||
expect_exact: "(function(a,b,c){console.log(a-- >=b,a-- >=b+c,a+b-- >=c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "false false false -1 1 3"
|
||||
}
|
||||
|
||||
html_comment_in_right_shift: {
|
||||
input: {
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a-- >> b,
|
||||
a-- >> b + c,
|
||||
a + b-- >> c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "(function(a,b,c){console.log(a-- >>b,a-- >>b+c,a+b-- >>c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "0 0 0 -1 1 3"
|
||||
}
|
||||
|
||||
html_comment_in_zero_fill_right_shift: {
|
||||
input: {
|
||||
(function(a, b, c) {
|
||||
console.log(
|
||||
a-- >>> b,
|
||||
a-- >>> b + c,
|
||||
a + b-- >>> c,
|
||||
a, b, c
|
||||
);
|
||||
})(1, 2, 3);
|
||||
}
|
||||
expect_exact: "(function(a,b,c){console.log(a-- >>>b,a-- >>>b+c,a+b-- >>>c,a,b,c)})(1,2,3);"
|
||||
expect_stdout: "0 0 0 -1 1 3"
|
||||
}
|
||||
|
||||
html_comment_in_string_literal: {
|
||||
input: {
|
||||
function f() { return "<!--HTML-->comment in<!--string literal-->"; }
|
||||
console.log("<!--HTML-->comment in<!--string literal-->".length);
|
||||
}
|
||||
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
|
||||
expect_exact: 'console.log("\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e".length);'
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ non_hoisted_function_after_return: {
|
||||
}
|
||||
expect: {
|
||||
function foo(x) {
|
||||
return x ? bar() : baz();
|
||||
return (x ? bar : baz)();
|
||||
function bar() { return 7 }
|
||||
function baz() { return 8 }
|
||||
}
|
||||
@@ -181,7 +181,7 @@ non_hoisted_function_after_return_strict: {
|
||||
expect: {
|
||||
"use strict";
|
||||
function foo(x) {
|
||||
return x ? bar() : baz();
|
||||
return (x ? bar : baz)();
|
||||
function bar() { return 7 }
|
||||
function baz() { return 8 }
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ cond_5: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
some_condition() && some_other_condition() ? do_something() : alternate();
|
||||
(some_condition() && some_other_condition() ? do_something : alternate)();
|
||||
if (some_condition() && some_other_condition()) do_something();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,13 +873,13 @@ iife_func_side_effects: {
|
||||
function z() {
|
||||
console.log("z");
|
||||
}
|
||||
(function(a, b) {
|
||||
(function(b) {
|
||||
return function() {
|
||||
console.log("FAIL");
|
||||
} + b();
|
||||
})(x(), function() {
|
||||
})((x(), function() {
|
||||
return y();
|
||||
}, z());
|
||||
}), z());
|
||||
}
|
||||
expect_stdout: [
|
||||
"x",
|
||||
@@ -1155,3 +1155,303 @@ issue_3423_2: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
collapse_vars_repeated: {
|
||||
options = {
|
||||
booleans: true,
|
||||
collapse_vars: true,
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
hoist_funs: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
keep_fargs: "strict",
|
||||
loops: true,
|
||||
properties: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f1() {
|
||||
var dummy = 3, a = 5, unused = 2, a = 1, a = 3;
|
||||
return -a;
|
||||
}
|
||||
function f2(x) {
|
||||
var a = 3, a = x;
|
||||
return a;
|
||||
}
|
||||
(function(x) {
|
||||
var a = "GOOD" + x, e = "BAD", k = "!", e = a;
|
||||
console.log(e + k);
|
||||
})("!"),
|
||||
(function(x) {
|
||||
var a = "GOOD" + x, e = "BAD" + x, k = "!", e = a;
|
||||
console.log(e + k);
|
||||
})("!");
|
||||
}
|
||||
expect: {
|
||||
function f1() {
|
||||
return -3;
|
||||
}
|
||||
function f2(x) {
|
||||
return x;
|
||||
}
|
||||
(function() {
|
||||
console.log("GOOD!!");
|
||||
})(),
|
||||
(function() {
|
||||
console.log("GOOD!!");
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
chained_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
var c = a, c = b;
|
||||
b++;
|
||||
return c;
|
||||
}(1, 2));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b) {
|
||||
var c = 1;
|
||||
c = b;
|
||||
b++;
|
||||
return c;
|
||||
}(2));
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
replace_all_var_scope: {
|
||||
rename = true
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
(function(r, a) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case a++:
|
||||
}
|
||||
})(--b, a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
(function(c) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case c++:
|
||||
}
|
||||
})((--b, a));
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "100 109"
|
||||
}
|
||||
|
||||
issue_1583: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function m(t) {
|
||||
(function(e) {
|
||||
t = e();
|
||||
})(function() {
|
||||
return (function(a) {
|
||||
return a;
|
||||
})(function(a) {});
|
||||
});
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function m(t) {
|
||||
(function() {
|
||||
(function() {
|
||||
return (function() {
|
||||
return function(a) {};
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issues_3267_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(x) {
|
||||
x();
|
||||
})(function() {
|
||||
(function(i) {
|
||||
if (i)
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
})(Object());
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
if (Object())
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
trailing_argument_side_effects: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(function(a, b) {
|
||||
return b || "PASS";
|
||||
}(f()));
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return "FAIL";
|
||||
}
|
||||
console.log(function(b) {
|
||||
return b || "PASS";
|
||||
}(void f()));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
recursive_iife_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
recursive_iife_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
}(null, 0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
}(0, 0));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
recursive_iife_3: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, c = "PASS";
|
||||
(function() {
|
||||
function f(b, d, e) {
|
||||
a-- && f(null, 42, 0);
|
||||
e && (c = "FAIL");
|
||||
d && d.p;
|
||||
}
|
||||
var a_1 = f();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, c = "PASS";
|
||||
(function() {
|
||||
(function f(b, d, e) {
|
||||
a-- && f(null, 42, 0);
|
||||
e && (c = "FAIL");
|
||||
d && d.p;
|
||||
})();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3619: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = "FAIL";
|
||||
(function f(c, d) {
|
||||
function g() {
|
||||
d && (b = "PASS", 0 <= --a && g());
|
||||
0 <= --a && f(0, "function");
|
||||
}
|
||||
g();
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = "FAIL";
|
||||
(function f(c, d) {
|
||||
function g() {
|
||||
d && (b = "PASS", 0 <= --a && g());
|
||||
0 <= --a && f(0, "function");
|
||||
}
|
||||
g();
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -574,9 +574,11 @@ issue_2740_3: {
|
||||
console.log(x, y);
|
||||
}
|
||||
expect: {
|
||||
L1: for (var x = 0; x < 3; x++)
|
||||
for (var y = 0; y < 2; y++)
|
||||
L1: for (var x = 0; x < 3; x++) {
|
||||
var y = 0;
|
||||
if (y < 2)
|
||||
break L1;
|
||||
}
|
||||
console.log(x, y);
|
||||
}
|
||||
expect_stdout: "0 0"
|
||||
@@ -753,3 +755,175 @@ empty_for_in_side_effects: {
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3631_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
L: do {
|
||||
for (;;) continue L;
|
||||
var b = 1;
|
||||
} while (b && c++);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
do {
|
||||
var b;
|
||||
} while (b && c++);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_3631_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
L: for (var a = 1; a--; console.log(b)) {
|
||||
for (;;) continue L;
|
||||
var b = "FAIL";
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (var a = 1; a--; console.log(b))
|
||||
var b;
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
loop_if_break: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b) {
|
||||
try {
|
||||
while (a) {
|
||||
if (b) {
|
||||
break;
|
||||
var c = 42;
|
||||
console.log(c);
|
||||
} else {
|
||||
var d = false;
|
||||
throw d;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("E:", e);
|
||||
}
|
||||
console.log(a, b, c, d);
|
||||
}
|
||||
f(0, 0);
|
||||
f(0, 1);
|
||||
f(1, 0);
|
||||
f(1, 1);
|
||||
}
|
||||
expect: {
|
||||
function f(a, b) {
|
||||
try {
|
||||
for (;a && !b;) {
|
||||
var d = false;
|
||||
throw d;
|
||||
var c;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("E:", e);
|
||||
}
|
||||
console.log(a, b, c, d);
|
||||
}
|
||||
f(0, 0);
|
||||
f(0, 1);
|
||||
f(1, 0);
|
||||
f(1, 1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0 undefined undefined",
|
||||
"0 1 undefined undefined",
|
||||
"E: false",
|
||||
"1 0 undefined false",
|
||||
"1 1 undefined undefined",
|
||||
]
|
||||
}
|
||||
|
||||
loop_return: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
while (a) return 42;
|
||||
return "foo";
|
||||
}
|
||||
console.log(f(0), f(1));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
if (a) return 42;
|
||||
return "foo";
|
||||
}
|
||||
console.log(f(0), f(1));
|
||||
}
|
||||
expect_stdout: "foo 42"
|
||||
}
|
||||
|
||||
issue_3634_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
var b = 0;
|
||||
L: while (++b < 2)
|
||||
while (1)
|
||||
if (b) break L;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 0;
|
||||
L: for (;++b < 2;)
|
||||
for (;1;)
|
||||
if (b) break L;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3634_2: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
var b = 0;
|
||||
L: while (++b < 2)
|
||||
while (1)
|
||||
if (!b)
|
||||
continue L;
|
||||
else
|
||||
break L;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 0;
|
||||
L: for (;++b < 2;)
|
||||
for (;1;)
|
||||
if (!b)
|
||||
continue L;
|
||||
else
|
||||
break L;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -6774,3 +6774,76 @@ issue_3509: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3622: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
!function(b, a) {
|
||||
a && (c = "PASS");
|
||||
}(42, this);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
var a;
|
||||
a = this,
|
||||
!void (a && (c = "PASS")),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3631_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
L: do {
|
||||
for (;;) continue L;
|
||||
var b = 1;
|
||||
} while (b && c++);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
L: do {
|
||||
for (;;) continue L;
|
||||
var b = 1;
|
||||
} while (b && c++);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_3631_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
L: for (var a = 1; a--; console.log(b)) {
|
||||
for (;;) continue L;
|
||||
var b = "FAIL";
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
L: for (var a = 1; a--; console.log(b)) {
|
||||
for (;;) continue L;
|
||||
var b = "FAIL";
|
||||
}
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -69,13 +69,13 @@ describe("Directives", function() {
|
||||
],
|
||||
[
|
||||
'"use \\\nstrict";"use strict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
[ "use strict" ],
|
||||
[ "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'"\\76";',
|
||||
[],
|
||||
[ ">", "\\76" ]
|
||||
[ "\\76" ],
|
||||
[ ">" ]
|
||||
],
|
||||
[
|
||||
// no ; or newline
|
||||
@@ -106,13 +106,13 @@ describe("Directives", function() {
|
||||
],
|
||||
[
|
||||
'function foo() {"use \\\nstrict";"use strict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
[ "use strict" ],
|
||||
[ "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'var foo = function() {"\\76";',
|
||||
[],
|
||||
[ ">", "\\76" ]
|
||||
[ "\\76" ],
|
||||
[ ">" ]
|
||||
],
|
||||
[
|
||||
'var foo = function() {"use strict"', // no ; or newline
|
||||
@@ -156,21 +156,24 @@ describe("Directives", function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should test EXPECT_DIRECTIVE RegExp", function() {
|
||||
it("Should print semicolon to separate strings from directives", function() {
|
||||
[
|
||||
[ "", true ],
|
||||
[ "'test';", true ],
|
||||
[ "'test';;", true ],
|
||||
[ "'tests';\n", true ],
|
||||
[ "'tests'", false ],
|
||||
[ "'tests'; \n\t", true ],
|
||||
[ "'tests';\n\n", true ],
|
||||
[ "\n\n\"use strict\";\n\n", true ],
|
||||
[ "", ';"";' ],
|
||||
[ '"test";', '"test";;"";' ],
|
||||
[ '"test";;', '"test";;"";' ],
|
||||
[ '"tests";\n', '"tests";;"";' ],
|
||||
[ '"tests"', '"tests";;"";' ],
|
||||
[ '"tests"; \n\t', '"tests";;"";' ],
|
||||
[ '"tests";\n\n', '"tests";;"";' ],
|
||||
[ '\n\n"use strict";\n\n', '"use strict";;"";' ],
|
||||
].forEach(function(test) {
|
||||
var ast = UglifyJS.parse(test[0]);
|
||||
ast.body.push(new UglifyJS.AST_SimpleStatement({
|
||||
body: new UglifyJS.AST_String({ value: "" })
|
||||
}));
|
||||
var out = UglifyJS.OutputStream();
|
||||
out.print(test[0]);
|
||||
out.print_string("", null, true);
|
||||
assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]);
|
||||
ast.print(out);
|
||||
assert.strictEqual(out.get(), test[1], test[0]);
|
||||
});
|
||||
});
|
||||
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
|
||||
@@ -178,8 +181,8 @@ describe("Directives", function() {
|
||||
'"use strict";',
|
||||
"'use strict';",
|
||||
'"use strict";',
|
||||
'"use strict";;',
|
||||
"'use strict';",
|
||||
'"use strict";',
|
||||
";'use strict';",
|
||||
"console.log('use strict');"
|
||||
].join(""), {
|
||||
compress: false,
|
||||
@@ -201,19 +204,23 @@ describe("Directives", function() {
|
||||
it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() {
|
||||
[
|
||||
[
|
||||
'{"use\x20strict"}',
|
||||
'"use strict";"use\\x20strict";',
|
||||
'"use strict";"use\\x20strict";'
|
||||
],
|
||||
[
|
||||
'{"use\\x20strict"}',
|
||||
'{"use strict"}'
|
||||
],
|
||||
[
|
||||
'function foo(){"use\x20strict";}', // Valid place for directives
|
||||
'function foo(){"use strict"}'
|
||||
'function foo(){"use\\x20strict";}', // Valid place for directives
|
||||
'function foo(){"use\\x20strict"}'
|
||||
],
|
||||
[
|
||||
'try{"use\x20strict"}catch(e){}finally{"use\x20strict"}',
|
||||
'try{"use\\x20strict"}catch(e){}finally{"use\\x20strict"}',
|
||||
'try{"use strict"}catch(e){}finally{"use strict"}'
|
||||
],
|
||||
[
|
||||
'if(1){"use\x20strict"} else {"use strict"}',
|
||||
'if(1){"use\\x20strict"} else {"use strict"}',
|
||||
'if(1){"use strict"}else{"use strict"}'
|
||||
]
|
||||
].forEach(function(test) {
|
||||
@@ -225,16 +232,6 @@ describe("Directives", function() {
|
||||
assert.strictEqual(result.code, test[1], test[0]);
|
||||
});
|
||||
});
|
||||
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
|
||||
var result = UglifyJS.minify('"use strict";"use\\x20strict";', {
|
||||
compress: false,
|
||||
output: {
|
||||
semicolons: false
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '"use strict";;"use strict"\n');
|
||||
});
|
||||
it("Should check quote style of directives", function() {
|
||||
[
|
||||
// 0. Prefer double quotes, unless string contains more double quotes than single quotes
|
||||
@@ -249,9 +246,9 @@ describe("Directives", function() {
|
||||
'"use strict";'
|
||||
],
|
||||
[
|
||||
'"\\\'use strict\\\'";', // Not a directive as it contains quotes
|
||||
'"\\\'use strict\\\'";',
|
||||
0,
|
||||
';"\'use strict\'";',
|
||||
'"\\\'use strict\\\'";',
|
||||
],
|
||||
[
|
||||
"'\"use strict\"';",
|
||||
@@ -273,7 +270,7 @@ describe("Directives", function() {
|
||||
'"\'use strict\'";',
|
||||
1,
|
||||
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||
"'\\'use strict\\'';",
|
||||
'"\'use strict\'";',
|
||||
],
|
||||
[
|
||||
"'\\'use strict\\'';", // Not a valid directive
|
||||
@@ -305,7 +302,7 @@ describe("Directives", function() {
|
||||
"'\"use strict\"';",
|
||||
2,
|
||||
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||
'"\\\"use strict\\\"";',
|
||||
"'\"use strict\"';",
|
||||
],
|
||||
[
|
||||
'"\\"use strict\\"";', // Not a valid directive
|
||||
@@ -353,8 +350,7 @@ describe("Directives", function() {
|
||||
[
|
||||
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
||||
'"use asm";"use\\x20strict";1+1;',
|
||||
// Yet, the parser noticed that "use strict" wasn't a directive
|
||||
'"use asm";;"use strict";1+1;',
|
||||
'"use asm";"use\\x20strict";1+1;'
|
||||
],
|
||||
[
|
||||
'function f(){ "use strict" }',
|
||||
|
||||
@@ -59,13 +59,13 @@ describe("String literals", function() {
|
||||
|
||||
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||
var tests = [
|
||||
['"\\76";', ';">";'],
|
||||
['"\\0"', '"\\0";'],
|
||||
['"\\08"', '"\\x008";'],
|
||||
['"\\008"', '"\\x008";'],
|
||||
['"\\0008"', '"\\x008";'],
|
||||
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
||||
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
||||
[ ';"\\76";', ';">";' ],
|
||||
[ ';"\\0";', ';"\\0";' ],
|
||||
[ ';"\\08"', ';"\\x008";' ],
|
||||
[ ';"\\008"', ';"\\x008";' ],
|
||||
[ ';"\\0008"', ';"\\x008";' ],
|
||||
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
|
||||
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
|
||||
];
|
||||
|
||||
for (var test in tests) {
|
||||
@@ -75,8 +75,8 @@ describe("String literals", function() {
|
||||
});
|
||||
|
||||
it("Should not throw error when digit is 8 or 9", function() {
|
||||
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
|
||||
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
|
||||
});
|
||||
|
||||
it("Should not unescape unpaired surrogates", function() {
|
||||
@@ -93,7 +93,7 @@ describe("String literals", function() {
|
||||
for (; i <= 0xFFFF; i++) {
|
||||
code.push("\\u" + i.toString(16));
|
||||
}
|
||||
code = '"' + code.join() + '"';
|
||||
code = ';"' + code.join() + '"';
|
||||
var normal = UglifyJS.minify(code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
|
||||
@@ -1089,6 +1089,19 @@ function log(options) {
|
||||
}
|
||||
}
|
||||
|
||||
function fuzzy_match(original, uglified) {
|
||||
original = original.split(" ", 5);
|
||||
uglified = uglified.split(" ", 5);
|
||||
for (var i = 0; i < 5; i++) {
|
||||
if (original[i] === uglified[i]) continue;
|
||||
var a = +original[i];
|
||||
var b = +uglified[i];
|
||||
if (Math.abs((b - a) / a) < 1e-10) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var fallback_options = [ JSON.stringify({
|
||||
compress: false,
|
||||
mangle: false
|
||||
@@ -1111,8 +1124,12 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
uglify_code = uglify_code.code;
|
||||
uglify_result = sandbox.run_code(uglify_code, o.toplevel);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
if (!ok && o.compress.unsafe_math) {
|
||||
ok = sandbox.same_stdout(sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3")), uglify_result, o.toplevel);
|
||||
if (!ok && typeof uglify_result == "string" && o.compress.unsafe_math) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uglify_code = uglify_code.error;
|
||||
|
||||
@@ -12,17 +12,16 @@ function spawn(endTime) {
|
||||
], {
|
||||
stdio: [ "ignore", "pipe", "pipe" ]
|
||||
}).on("exit", respawn);
|
||||
var line = "";
|
||||
var stdout = "";
|
||||
child.stdout.on("data", function(data) {
|
||||
line += data;
|
||||
stdout += data;
|
||||
});
|
||||
child.stderr.once("data", function() {
|
||||
process.exitCode = 1;
|
||||
}).pipe(process.stdout);
|
||||
var stderr = "";
|
||||
child.stderr.on("data", trap).pipe(process.stdout);
|
||||
var keepAlive = setInterval(function() {
|
||||
var end = line.lastIndexOf("\r");
|
||||
console.log(line.slice(line.lastIndexOf("\r", end - 1) + 1, end));
|
||||
line = line.slice(end + 1);
|
||||
var end = stdout.lastIndexOf("\r");
|
||||
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
||||
stdout = stdout.slice(end + 1);
|
||||
}, ping);
|
||||
var timer = setTimeout(function() {
|
||||
clearInterval(keepAlive);
|
||||
@@ -31,9 +30,17 @@ function spawn(endTime) {
|
||||
}, endTime - Date.now());
|
||||
|
||||
function respawn() {
|
||||
console.log(line);
|
||||
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
|
||||
clearInterval(keepAlive);
|
||||
clearTimeout(timer);
|
||||
spawn(endTime);
|
||||
}
|
||||
|
||||
function trap(data) {
|
||||
stderr += data;
|
||||
if (~stderr.indexOf("\nminify(options):\n")) {
|
||||
process.exitCode = 1;
|
||||
child.stderr.removeListener("data", trap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user