Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1a77e4fc0 | ||
|
|
b55a2fd531 | ||
|
|
e8a2c0b5bf | ||
|
|
21cd7e3f57 | ||
|
|
5172ba5f2a | ||
|
|
a57b069409 | ||
|
|
4454656c3b | ||
|
|
fa43768ce0 | ||
|
|
a74e600fa0 | ||
|
|
4b21526310 | ||
|
|
a7a7b1daed | ||
|
|
7436977aa5 | ||
|
|
e3c565b46f | ||
|
|
54b0b49b68 | ||
|
|
65648d84a5 | ||
|
|
fd788590f6 | ||
|
|
143f9054da | ||
|
|
f2286c33f1 | ||
|
|
b9615f7a62 | ||
|
|
c520e99eda | ||
|
|
615ae37ca3 | ||
|
|
7aa7f21872 | ||
|
|
4430a436eb |
@@ -605,6 +605,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `arguments` (default: `true`) -- replace `arguments[index]` with function
|
||||
parameter name whenever possible.
|
||||
|
||||
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
|
||||
|
||||
- `booleans` (default: `true`) -- various optimizations for boolean context,
|
||||
for example `!!a ? b : c → a ? b : c`
|
||||
|
||||
@@ -634,6 +636,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `expression` (default: `false`) -- Pass `true` to preserve completion values
|
||||
from terminal statements without `return`, e.g. in bookmarklets.
|
||||
|
||||
- `functions` (default: `true`) -- convert declarations from `var`to `function`
|
||||
whenever possible.
|
||||
|
||||
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
|
||||
|
||||
- `hoist_funs` (default: `false`) -- hoist function declarations
|
||||
|
||||
323
lib/compress.js
323
lib/compress.js
@@ -49,6 +49,7 @@ function Compressor(options, false_by_default) {
|
||||
TreeTransformer.call(this, this.before, this.after);
|
||||
this.options = defaults(options, {
|
||||
arguments : !false_by_default,
|
||||
assignments : !false_by_default,
|
||||
booleans : !false_by_default,
|
||||
collapse_vars : !false_by_default,
|
||||
comparisons : !false_by_default,
|
||||
@@ -59,6 +60,7 @@ function Compressor(options, false_by_default) {
|
||||
drop_debugger : !false_by_default,
|
||||
evaluate : !false_by_default,
|
||||
expression : false,
|
||||
functions : !false_by_default,
|
||||
global_defs : false,
|
||||
hoist_funs : false,
|
||||
hoist_props : !false_by_default,
|
||||
@@ -149,7 +151,7 @@ Compressor.prototype = new TreeTransformer;
|
||||
merge(Compressor.prototype, {
|
||||
option: function(key) { return this.options[key] },
|
||||
exposed: function(def) {
|
||||
if (def.global) for (var i = 0, len = def.orig.length; i < len; i++)
|
||||
if (def.global) for (var i = 0; i < def.orig.length; i++)
|
||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||
return true;
|
||||
return false;
|
||||
@@ -537,13 +539,11 @@ merge(Compressor.prototype, {
|
||||
var d = sym.definition();
|
||||
var safe = safe_to_assign(tw, d, sym.scope, node.right);
|
||||
d.assignments++;
|
||||
if (!safe) return;
|
||||
var fixed = d.fixed;
|
||||
if (!fixed && node.operator != "=") return;
|
||||
var eq = node.operator == "=";
|
||||
var value = eq ? node.right : node;
|
||||
if (is_modified(compressor, tw, node, value, 0)) return;
|
||||
d.references.push(sym);
|
||||
if (!eq) d.chained = true;
|
||||
d.fixed = eq ? function() {
|
||||
return node.right;
|
||||
@@ -554,6 +554,8 @@ merge(Compressor.prototype, {
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
if (!safe) return;
|
||||
d.references.push(sym);
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
@@ -783,10 +785,8 @@ merge(Compressor.prototype, {
|
||||
var d = exp.definition();
|
||||
var safe = safe_to_assign(tw, d, exp.scope, true);
|
||||
d.assignments++;
|
||||
if (!safe) return;
|
||||
var fixed = d.fixed;
|
||||
if (!fixed) return;
|
||||
d.references.push(exp);
|
||||
d.chained = true;
|
||||
d.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
@@ -800,6 +800,8 @@ merge(Compressor.prototype, {
|
||||
})
|
||||
});
|
||||
};
|
||||
if (!safe) return;
|
||||
d.references.push(exp);
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
});
|
||||
@@ -1100,10 +1102,10 @@ merge(Compressor.prototype, {
|
||||
stop_if_hit = parent;
|
||||
}
|
||||
// Replace variable with assignment when found
|
||||
var hit_lhs, hit_rhs;
|
||||
var hit_rhs;
|
||||
if (can_replace
|
||||
&& !(node instanceof AST_SymbolDeclaration)
|
||||
&& (scan_lhs && (hit_lhs = lhs.equivalent_to(node))
|
||||
&& (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;
|
||||
@@ -1193,10 +1195,9 @@ merge(Compressor.prototype, {
|
||||
var stop_after = null;
|
||||
var stop_if_hit = null;
|
||||
var lhs = get_lhs(candidate);
|
||||
var rhs = get_rhs(candidate);
|
||||
var side_effects = lhs && lhs.has_side_effects(compressor);
|
||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs);
|
||||
var scan_rhs = rhs && foldable(rhs);
|
||||
var scan_rhs = foldable(get_rhs(candidate));
|
||||
if (!scan_lhs && !scan_rhs) continue;
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
var lvalues = get_lvalues(candidate);
|
||||
@@ -1241,7 +1242,7 @@ merge(Compressor.prototype, {
|
||||
// Scan case expressions first in a switch statement
|
||||
if (node instanceof AST_Switch) {
|
||||
node.expression = node.expression.transform(scanner);
|
||||
for (var i = 0, len = node.body.length; !abort && i < len; i++) {
|
||||
for (var i = 0; !abort && i < node.body.length; i++) {
|
||||
var branch = node.body[i];
|
||||
if (branch instanceof AST_Case) {
|
||||
if (!hit) {
|
||||
@@ -1361,6 +1362,7 @@ merge(Compressor.prototype, {
|
||||
hit_stack.push(expr);
|
||||
if (expr instanceof AST_Assign) {
|
||||
candidates.push(hit_stack.slice());
|
||||
extract_candidates(expr.left);
|
||||
extract_candidates(expr.right);
|
||||
} else if (expr instanceof AST_Binary) {
|
||||
extract_candidates(expr.left);
|
||||
@@ -1376,6 +1378,8 @@ merge(Compressor.prototype, {
|
||||
extract_candidates(expr.alternative);
|
||||
} else if (expr instanceof AST_Definitions) {
|
||||
expr.definitions.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_Dot) {
|
||||
extract_candidates(expr.expression);
|
||||
} else if (expr instanceof AST_DWLoop) {
|
||||
extract_candidates(expr.condition);
|
||||
if (!(expr.body instanceof AST_Block)) {
|
||||
@@ -1407,6 +1411,9 @@ merge(Compressor.prototype, {
|
||||
expr.expressions.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_SimpleStatement) {
|
||||
extract_candidates(expr.body);
|
||||
} else if (expr instanceof AST_Sub) {
|
||||
extract_candidates(expr.expression);
|
||||
extract_candidates(expr.property);
|
||||
} else if (expr instanceof AST_Switch) {
|
||||
extract_candidates(expr.expression);
|
||||
expr.body.forEach(extract_candidates);
|
||||
@@ -1465,6 +1472,7 @@ merge(Compressor.prototype, {
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_PropAccess) return node;
|
||||
if (parent instanceof AST_Sequence) {
|
||||
return find_stop(parent, level + 1, parent.tail_node() !== node);
|
||||
}
|
||||
@@ -1523,6 +1531,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function foldable(expr) {
|
||||
if (!expr) return false;
|
||||
if (expr instanceof AST_SymbolRef) {
|
||||
var value = expr.evaluate(compressor);
|
||||
if (value === expr) return rhs_exact_match;
|
||||
@@ -1544,10 +1553,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}));
|
||||
return !circular && rhs_exact_match;
|
||||
}
|
||||
|
||||
function rhs_exact_match(node) {
|
||||
return rhs.equivalent_to(node);
|
||||
function rhs_exact_match(node) {
|
||||
return expr.equivalent_to(node);
|
||||
}
|
||||
}
|
||||
|
||||
function rhs_fuzzy_match(value, fallback) {
|
||||
@@ -1879,7 +1888,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function next_index(i) {
|
||||
for (var j = i + 1, len = statements.length; j < len; j++) {
|
||||
for (var j = i + 1; j < statements.length; j++) {
|
||||
var stat = statements[j];
|
||||
if (!(stat instanceof AST_Var && declarations_only(stat))) {
|
||||
break;
|
||||
@@ -1970,7 +1979,7 @@ merge(Compressor.prototype, {
|
||||
function to_simple_statement(block, decls) {
|
||||
if (!(block instanceof AST_BlockStatement)) return block;
|
||||
var stat = null;
|
||||
for (var i = 0, len = block.body.length; i < len; i++) {
|
||||
for (var i = 0; i < block.body.length; i++) {
|
||||
var line = block.body[i];
|
||||
if (line instanceof AST_Var && declarations_only(line)) {
|
||||
decls.push(line);
|
||||
@@ -2110,7 +2119,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function join_consecutive_vars(statements) {
|
||||
var defs;
|
||||
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||
for (var i = 0, j = -1; i < statements.length; i++) {
|
||||
var stat = statements[i];
|
||||
var prev = statements[j];
|
||||
if (stat instanceof AST_Definitions) {
|
||||
@@ -2238,7 +2247,11 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_SymbolRef, function() {
|
||||
var fixed = this.fixed_value();
|
||||
return fixed && fixed.is_truthy();
|
||||
if (!fixed) return false;
|
||||
this.is_truthy = return_false;
|
||||
var result = fixed.is_truthy();
|
||||
delete this.is_truthy;
|
||||
return result;
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_truthy", func);
|
||||
@@ -2251,45 +2264,38 @@ merge(Compressor.prototype, {
|
||||
return !compressor.option("pure_getters")
|
||||
|| this._dot_throw(compressor);
|
||||
});
|
||||
|
||||
function is_strict(compressor) {
|
||||
return /strict/.test(compressor.option("pure_getters"));
|
||||
}
|
||||
|
||||
def(AST_Node, is_strict);
|
||||
def(AST_Null, return_true);
|
||||
def(AST_Undefined, return_true);
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Array, return_false);
|
||||
def(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||
return false;
|
||||
});
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator == "="
|
||||
&& this.right._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Binary, function(compressor) {
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent._dot_throw(compressor)
|
||||
|| this.alternative._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Dot, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
var exp = this.expression;
|
||||
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
||||
return !(exp instanceof AST_Lambda && this.property == "prototype");
|
||||
});
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_Null, return_true);
|
||||
def(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||
return false;
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node()._dot_throw(compressor);
|
||||
});
|
||||
@@ -2299,8 +2305,17 @@ merge(Compressor.prototype, {
|
||||
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||
if (this.is_immutable()) return false;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._dot_throw(compressor);
|
||||
if (!fixed) return true;
|
||||
this._dot_throw = return_true;
|
||||
var result = fixed._dot_throw(compressor);
|
||||
delete this._dot_throw;
|
||||
return result;
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_Undefined, return_true);
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_dot_throw", func);
|
||||
});
|
||||
@@ -2334,6 +2349,14 @@ merge(Compressor.prototype, {
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_boolean(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_boolean = return_false;
|
||||
var result = fixed.is_boolean(compressor);
|
||||
delete this.is_boolean;
|
||||
return result;
|
||||
});
|
||||
var unary = makePredicate("! delete");
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return unary[this.operator];
|
||||
@@ -2415,6 +2438,14 @@ merge(Compressor.prototype, {
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_number(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_number = return_false;
|
||||
var result = fixed.is_number(compressor);
|
||||
delete this.is_number;
|
||||
return result;
|
||||
});
|
||||
var unary = makePredicate("+ - ~ ++ --");
|
||||
def(AST_Unary, function() {
|
||||
return unary[this.operator];
|
||||
@@ -2426,22 +2457,30 @@ merge(Compressor.prototype, {
|
||||
// methods to determine if an expression has a string result type
|
||||
(function(def) {
|
||||
def(AST_Node, return_false);
|
||||
def(AST_String, return_true);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
def(AST_Assign, function(compressor) {
|
||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
return this.operator == "+" &&
|
||||
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
||||
});
|
||||
def(AST_Assign, function(compressor) {
|
||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_string(compressor);
|
||||
});
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||
def(AST_String, return_true);
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_string = return_false;
|
||||
var result = fixed.is_string(compressor);
|
||||
delete this.is_string;
|
||||
return result;
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_string", func);
|
||||
@@ -2681,7 +2720,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Array, function(compressor, cached, depth) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var elements = [];
|
||||
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||
for (var i = 0; i < this.elements.length; i++) {
|
||||
var element = this.elements[i];
|
||||
var value = element._eval(compressor, cached, depth);
|
||||
if (element === value) return this;
|
||||
@@ -2694,7 +2733,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Object, function(compressor, cached, depth) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var val = {};
|
||||
for (var i = 0, len = this.properties.length; i < len; i++) {
|
||||
for (var i = 0; i < this.properties.length; i++) {
|
||||
var prop = this.properties[i];
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Symbol) {
|
||||
@@ -2889,7 +2928,7 @@ merge(Compressor.prototype, {
|
||||
if (!native_fn || !native_fn[key]) return this;
|
||||
}
|
||||
var args = [];
|
||||
for (var i = 0, len = this.args.length; i < len; i++) {
|
||||
for (var i = 0; i < this.args.length; i++) {
|
||||
var arg = this.args[i];
|
||||
var value = arg._eval(compressor, cached, depth);
|
||||
if (arg === value) return this;
|
||||
@@ -3240,6 +3279,12 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
}
|
||||
def(AST_Node, return_false);
|
||||
def(AST_Array, function() {
|
||||
return all(this.elements);
|
||||
});
|
||||
def(AST_Binary, function() {
|
||||
return this.left.is_constant_expression() && this.right.is_constant_expression();
|
||||
});
|
||||
def(AST_Constant, return_true);
|
||||
def(AST_Lambda, function(scope) {
|
||||
var self = this;
|
||||
@@ -3268,21 +3313,15 @@ merge(Compressor.prototype, {
|
||||
}));
|
||||
return result;
|
||||
});
|
||||
def(AST_Unary, function() {
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
def(AST_Binary, function() {
|
||||
return this.left.is_constant_expression() && this.right.is_constant_expression();
|
||||
});
|
||||
def(AST_Array, function() {
|
||||
return all(this.elements);
|
||||
});
|
||||
def(AST_Object, function() {
|
||||
return all(this.properties);
|
||||
});
|
||||
def(AST_ObjectProperty, function() {
|
||||
return this.value.is_constant_expression();
|
||||
});
|
||||
def(AST_Unary, function() {
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_constant_expression", func);
|
||||
});
|
||||
@@ -3425,9 +3464,7 @@ merge(Compressor.prototype, {
|
||||
if (node instanceof AST_Definitions && scope === self) {
|
||||
node.definitions.forEach(function(def) {
|
||||
var node_def = def.name.definition();
|
||||
if (def.name instanceof AST_SymbolVar) {
|
||||
var_defs_by_id.add(node_def.id, def);
|
||||
}
|
||||
var_defs_by_id.add(node_def.id, def);
|
||||
if (!drop_vars) {
|
||||
if (!(node_def.id in in_use_ids)) {
|
||||
in_use_ids[node_def.id] = true;
|
||||
@@ -3534,29 +3571,40 @@ merge(Compressor.prototype, {
|
||||
if (def.value && sym.id in fixed_ids && fixed_ids[sym.id] !== def) {
|
||||
def.value = def.value.drop_side_effect_free(compressor);
|
||||
}
|
||||
if (def.name instanceof AST_SymbolVar) {
|
||||
var var_defs = var_defs_by_id.get(sym.id);
|
||||
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
|
||||
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
if (def.value) {
|
||||
var ref = make_node(AST_SymbolRef, def.name, def.name);
|
||||
sym.references.push(ref);
|
||||
var assign = make_node(AST_Assign, def, {
|
||||
operator: "=",
|
||||
left: ref,
|
||||
right: def.value
|
||||
});
|
||||
if (fixed_ids[sym.id] === def) {
|
||||
fixed_ids[sym.id] = assign;
|
||||
}
|
||||
side_effects.push(assign.transform(tt));
|
||||
var var_defs = var_defs_by_id.get(sym.id);
|
||||
if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
|
||||
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
if (def.value) {
|
||||
var ref = make_node(AST_SymbolRef, def.name, def.name);
|
||||
sym.references.push(ref);
|
||||
var assign = make_node(AST_Assign, def, {
|
||||
operator: "=",
|
||||
left: ref,
|
||||
right: def.value
|
||||
});
|
||||
if (fixed_ids[sym.id] === def) {
|
||||
fixed_ids[sym.id] = assign;
|
||||
}
|
||||
remove(var_defs, def);
|
||||
sym.eliminated++;
|
||||
return;
|
||||
side_effects.push(assign.transform(tt));
|
||||
}
|
||||
remove(var_defs, def);
|
||||
sym.eliminated++;
|
||||
return;
|
||||
}
|
||||
if (def.value) {
|
||||
if (!def.value) {
|
||||
head.push(def);
|
||||
} else if (compressor.option("functions")
|
||||
&& def.value === def.name.fixed_value()
|
||||
&& def.value instanceof AST_Function
|
||||
&& !def.value.name
|
||||
&& !def.value.variables.get(def.name.name)
|
||||
&& (!compressor.has_directive("use strict") || parent instanceof AST_Scope)) {
|
||||
compressor.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
||||
var defun = make_node(AST_Defun, def, def.value);
|
||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||
def.name.scope.resolve().def_function(defun.name);
|
||||
body.push(defun);
|
||||
} else {
|
||||
if (side_effects.length > 0) {
|
||||
if (tail.length > 0) {
|
||||
side_effects.push(def.value);
|
||||
@@ -3569,8 +3617,6 @@ merge(Compressor.prototype, {
|
||||
side_effects = [];
|
||||
}
|
||||
tail.push(def);
|
||||
} else {
|
||||
head.push(def);
|
||||
}
|
||||
} else if (sym.orig[0] instanceof AST_SymbolCatch) {
|
||||
var value = def.value && def.value.drop_side_effect_free(compressor);
|
||||
@@ -3992,17 +4038,17 @@ merge(Compressor.prototype, {
|
||||
return this;
|
||||
});
|
||||
def(AST_Binary, function(compressor, first_in_statement) {
|
||||
var right = this.right.drop_side_effect_free(compressor);
|
||||
var right = this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (lazy_op[this.operator]) {
|
||||
if (right === this.right) return this;
|
||||
var node = this.clone();
|
||||
node.right = right;
|
||||
node.right = right.drop_side_effect_free(compressor);
|
||||
return node;
|
||||
} else {
|
||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||
return make_sequence(this, [ left, right ]);
|
||||
if (!left) return right;
|
||||
return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]);
|
||||
}
|
||||
});
|
||||
def(AST_Call, function(compressor, first_in_statement) {
|
||||
@@ -4062,19 +4108,6 @@ merge(Compressor.prototype, {
|
||||
def(AST_Function, function(compressor) {
|
||||
return this.name && compressor.option("ie8") ? this : null;
|
||||
});
|
||||
def(AST_Unary, function(compressor, first_in_statement) {
|
||||
if (unary_side_effects[this.operator]) {
|
||||
this.write_only = !this.expression.has_side_effects(compressor);
|
||||
return this;
|
||||
}
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator == "!") return this;
|
||||
return expression.negate(compressor, first_in_statement);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
def(AST_Object, function(compressor, first_in_statement) {
|
||||
var values = trim(this.properties, compressor, first_in_statement);
|
||||
return values && make_sequence(this, values);
|
||||
@@ -4082,12 +4115,10 @@ merge(Compressor.prototype, {
|
||||
def(AST_ObjectProperty, function(compressor, first_in_statement) {
|
||||
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
var last = this.tail_node();
|
||||
var expr = last.drop_side_effect_free(compressor);
|
||||
if (expr === last) return this;
|
||||
var expressions = this.expressions.slice(0, -1);
|
||||
if (expr) expressions.push(expr);
|
||||
def(AST_Sequence, function(compressor, first_in_statement) {
|
||||
var expressions = trim(this.expressions, compressor, first_in_statement);
|
||||
if (expressions === this.expressions) return this;
|
||||
if (!expressions) return null;
|
||||
return make_sequence(this, expressions);
|
||||
});
|
||||
def(AST_Sub, function(compressor, first_in_statement) {
|
||||
@@ -4099,9 +4130,27 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(this, [ expression, property ]);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
return this.is_declared(compressor) ? null : this;
|
||||
if (!this.is_declared(compressor)) return this;
|
||||
this.definition().replaced++;
|
||||
return null;
|
||||
});
|
||||
def(AST_This, return_null);
|
||||
def(AST_Unary, function(compressor, first_in_statement) {
|
||||
if (unary_side_effects[this.operator]) {
|
||||
this.write_only = !this.expression.has_side_effects(compressor);
|
||||
return this;
|
||||
}
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) {
|
||||
this.expression.definition().replaced++;
|
||||
return null;
|
||||
}
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator == "!") return this;
|
||||
return expression.negate(compressor, first_in_statement);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("drop_side_effect_free", func);
|
||||
});
|
||||
@@ -4596,9 +4645,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Definitions, function(self, compressor) {
|
||||
if (self.definitions.length == 0)
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
return self;
|
||||
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
||||
});
|
||||
|
||||
AST_Call.DEFMETHOD("lift_sequences", function(compressor) {
|
||||
@@ -4630,7 +4677,7 @@ merge(Compressor.prototype, {
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.pinned()) {
|
||||
var pos = 0, last = 0;
|
||||
for (var i = 0, len = self.args.length; i < len; i++) {
|
||||
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);
|
||||
@@ -4652,12 +4699,30 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("unsafe")) {
|
||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||
case "Array":
|
||||
if (self.args.length != 1) {
|
||||
return make_node(AST_Array, self, {
|
||||
elements: self.args
|
||||
}).optimize(compressor);
|
||||
if (self.args.length == 1) {
|
||||
var first = self.args[0];
|
||||
if (first instanceof AST_Number) try {
|
||||
var length = first.getValue();
|
||||
if (length > 6) break;
|
||||
var elements = Array(length);
|
||||
for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
|
||||
return make_node(AST_Array, self, {
|
||||
elements: elements
|
||||
});
|
||||
} catch (ex) {
|
||||
compressor.warn("Invalid array length: {length} [{file}:{line},{col}]", {
|
||||
length: length,
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col
|
||||
});
|
||||
break;
|
||||
}
|
||||
if (!first.is_boolean(compressor) && !first.is_string(compressor)) break;
|
||||
}
|
||||
break;
|
||||
return make_node(AST_Array, self, {
|
||||
elements: self.args
|
||||
});
|
||||
case "Object":
|
||||
if (self.args.length == 0) {
|
||||
return make_node(AST_Object, self, {
|
||||
@@ -4990,7 +5055,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function can_inject_args(catches, safe_to_inject) {
|
||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||
for (var i = 0; i < fn.argnames.length; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg.__unused) continue;
|
||||
if (!safe_to_inject
|
||||
@@ -5005,8 +5070,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function can_inject_vars(catches, safe_to_inject) {
|
||||
var len = fn.body.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
for (var i = 0; i < fn.body.length; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
if (!safe_to_inject) return false;
|
||||
@@ -5035,7 +5099,8 @@ merge(Compressor.prototype, {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope));
|
||||
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||
var safe_to_inject = (!(scope instanceof AST_Toplevel) || compressor.toplevel.vars)
|
||||
&& (exp !== fn || fn.parent_scope === compressor.find_parent(AST_Scope));
|
||||
var inline = compressor.option("inline");
|
||||
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||
@@ -5085,10 +5150,10 @@ merge(Compressor.prototype, {
|
||||
|
||||
function flatten_vars(decls, expressions) {
|
||||
var pos = expressions.length;
|
||||
for (var i = 0, lines = fn.body.length; i < lines; i++) {
|
||||
for (var i = 0; i < fn.body.length; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
|
||||
for (var j = 0; j < stat.definitions.length; j++) {
|
||||
var var_def = stat.definitions[j];
|
||||
var name = var_def.name;
|
||||
var redef = name.definition().redefined();
|
||||
@@ -5844,6 +5909,7 @@ merge(Compressor.prototype, {
|
||||
value = fixed.optimize(compressor);
|
||||
if (value === fixed) value = fixed.clone(true);
|
||||
}
|
||||
def.replaced++;
|
||||
return value;
|
||||
}
|
||||
if (fixed && def.should_replace === undefined) {
|
||||
@@ -5886,7 +5952,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (def.should_replace) {
|
||||
return def.should_replace();
|
||||
var value = def.should_replace();
|
||||
def.replaced++;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
@@ -6010,6 +6078,7 @@ merge(Compressor.prototype, {
|
||||
|| parent instanceof AST_Sequence && parent.tail_node() === node);
|
||||
}
|
||||
self = self.lift_sequences(compressor);
|
||||
if (!compressor.option("assignments")) return self;
|
||||
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||
// x = expr1 OP expr2
|
||||
if (self.right.left instanceof AST_SymbolRef
|
||||
@@ -6028,6 +6097,16 @@ merge(Compressor.prototype, {
|
||||
self.right = self.right.left;
|
||||
}
|
||||
}
|
||||
if ((self.operator == "+=" || self.operator == "-=")
|
||||
&& self.left.is_number(compressor)
|
||||
&& self.right instanceof AST_Number
|
||||
&& self.right.getValue() === 1) {
|
||||
var op = self.operator.slice(0, -1);
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator: op + op,
|
||||
expression: self.left
|
||||
});
|
||||
}
|
||||
return self;
|
||||
|
||||
function in_try(level, node) {
|
||||
|
||||
@@ -123,7 +123,7 @@ function OutputStream(options) {
|
||||
});
|
||||
} : function(str) {
|
||||
var s = "";
|
||||
for (var i = 0, len = str.length; i < len; i++) {
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|
||||
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
|
||||
s += "\\u" + str.charCodeAt(i).toString(16);
|
||||
|
||||
10
lib/parse.js
10
lib/parse.js
@@ -164,10 +164,6 @@ function is_unicode_connector_punctuation(ch) {
|
||||
return UNICODE.connector_punctuation.test(ch);
|
||||
}
|
||||
|
||||
function is_identifier(name) {
|
||||
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
|
||||
}
|
||||
|
||||
function is_identifier_start(code) {
|
||||
return code == 36 || code == 95 || is_letter(code);
|
||||
}
|
||||
@@ -272,10 +268,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function find_eol() {
|
||||
var text = S.text;
|
||||
for (var i = S.pos, n = S.text.length; i < n; ++i) {
|
||||
var ch = text[i];
|
||||
if (NEWLINE_CHARS[ch])
|
||||
return i;
|
||||
for (var i = S.pos; i < S.text.length; ++i) {
|
||||
if (NEWLINE_CHARS[text[i]]) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
32
lib/scope.js
32
lib/scope.js
@@ -61,8 +61,6 @@ SymbolDef.next_id = 1;
|
||||
|
||||
SymbolDef.prototype = {
|
||||
unmangleable: function(options) {
|
||||
if (!options) options = {};
|
||||
|
||||
return this.global && !options.toplevel
|
||||
|| this.undeclared
|
||||
|| !options.eval && this.scope.pinned()
|
||||
@@ -198,24 +196,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
if (node instanceof AST_SymbolLambda) {
|
||||
var def = node.thedef;
|
||||
if (def.orig.length == 1) {
|
||||
redefine(node, node.scope.parent_scope);
|
||||
node.thedef.init = def.init;
|
||||
}
|
||||
redefine(node, node.scope.parent_scope);
|
||||
node.thedef.init = def.init;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
|
||||
function redefine(node, scope) {
|
||||
var name = node.name;
|
||||
var refs = node.thedef.references;
|
||||
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
||||
refs.forEach(function(ref) {
|
||||
ref.thedef = def;
|
||||
ref.reference(options);
|
||||
var old_def = node.thedef;
|
||||
var new_def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||
node.thedef = new_def;
|
||||
node.reference(options);
|
||||
});
|
||||
node.thedef = def;
|
||||
node.reference(options);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -300,7 +294,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
|
||||
AST_Lambda.DEFMETHOD("resolve", return_this);
|
||||
AST_Scope.DEFMETHOD("resolve", function() {
|
||||
return this.parent_scope;
|
||||
return this.parent_scope.resolve();
|
||||
});
|
||||
AST_Toplevel.DEFMETHOD("resolve", return_this);
|
||||
|
||||
@@ -337,7 +331,7 @@ function next_mangled_name(scope, options, def) {
|
||||
} while (scope = scope.parent_scope);
|
||||
});
|
||||
var name;
|
||||
for (var i = 0, len = holes.length; i < len; i++) {
|
||||
for (var i = 0; i < holes.length; i++) {
|
||||
name = base54(holes[i]);
|
||||
if (names[name]) continue;
|
||||
holes.splice(i, 1);
|
||||
@@ -346,7 +340,7 @@ function next_mangled_name(scope, options, def) {
|
||||
}
|
||||
while (true) {
|
||||
name = base54(++scope.cname);
|
||||
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue;
|
||||
if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
|
||||
if (!names[name]) break;
|
||||
holes.push(scope.cname);
|
||||
}
|
||||
@@ -426,7 +420,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
var name;
|
||||
do {
|
||||
name = base54(++lname);
|
||||
} while (!is_identifier(name));
|
||||
} while (RESERVED_WORDS[name]);
|
||||
node.mangled_name = name;
|
||||
return true;
|
||||
}
|
||||
@@ -497,7 +491,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
var name;
|
||||
do {
|
||||
name = base54(cname++);
|
||||
} while (avoid[name] || !is_identifier(name));
|
||||
} while (avoid[name] || RESERVED_WORDS[name]);
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -559,7 +553,7 @@ var base54 = (function() {
|
||||
var freq = Object.create(null);
|
||||
function init(chars) {
|
||||
var array = [];
|
||||
for (var i = 0, len = chars.length; i < len; i++) {
|
||||
for (var i = 0; i < chars.length; i++) {
|
||||
var ch = chars[i];
|
||||
array.push(ch);
|
||||
freq[ch] = -1e-2 * i;
|
||||
|
||||
@@ -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.4.10",
|
||||
"version": "3.5.5",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -23,12 +23,12 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.19.0",
|
||||
"commander": "~2.20.0",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~6.1.1",
|
||||
"semver": "~5.6.0"
|
||||
"semver": "~6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/run-tests.js"
|
||||
|
||||
@@ -239,3 +239,113 @@ index_length: {
|
||||
}
|
||||
expect_stdout: "1 2"
|
||||
}
|
||||
|
||||
constructor_bad: {
|
||||
options = {
|
||||
unsafe: true
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
new Array(NaN);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
new Array(3.14);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
expect_warnings: [
|
||||
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:13,12]",
|
||||
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:17,16]",
|
||||
]
|
||||
}
|
||||
|
||||
constructor_good: {
|
||||
options = {
|
||||
unsafe: true
|
||||
}
|
||||
input: {
|
||||
console.log(Array());
|
||||
console.log(Array(0));
|
||||
console.log(Array(1));
|
||||
console.log(Array(6));
|
||||
console.log(Array(7));
|
||||
console.log(Array(1, 2));
|
||||
console.log(Array(false));
|
||||
console.log(Array("foo"));
|
||||
console.log(Array(Array));
|
||||
console.log(new Array());
|
||||
console.log(new Array(0));
|
||||
console.log(new Array(1));
|
||||
console.log(new Array(6));
|
||||
console.log(new Array(7));
|
||||
console.log(new Array(1, 2));
|
||||
console.log(new Array(false));
|
||||
console.log(new Array("foo"));
|
||||
console.log(new Array(Array));
|
||||
}
|
||||
expect: {
|
||||
console.log([]);
|
||||
console.log([]);
|
||||
console.log([,]);
|
||||
console.log([,,,,,,]);
|
||||
console.log(Array(7));
|
||||
console.log([ 1, 2 ]);
|
||||
console.log([ false ]);
|
||||
console.log([ "foo" ]);
|
||||
console.log(Array(Array));
|
||||
console.log([]);
|
||||
console.log([]);
|
||||
console.log([,]);
|
||||
console.log([,,,,,,]);
|
||||
console.log(Array(7));
|
||||
console.log([ 1, 2 ]);
|
||||
console.log([ false ]);
|
||||
console.log([ "foo" ]);
|
||||
console.log(Array(Array));
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: []
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
asm_mixed: {
|
||||
options = {
|
||||
assignments: true,
|
||||
booleans: true,
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
op_equals_left_local_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -60,6 +61,7 @@ op_equals_left_local_var: {
|
||||
|
||||
op_equals_right_local_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -123,6 +125,7 @@ op_equals_right_local_var: {
|
||||
}
|
||||
op_equals_left_global_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -179,6 +182,7 @@ op_equals_left_global_var: {
|
||||
|
||||
op_equals_right_global_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -236,3 +240,52 @@ op_equals_right_global_var: {
|
||||
x = g() & x;
|
||||
}
|
||||
}
|
||||
|
||||
increment_decrement_1: {
|
||||
options = {
|
||||
assignments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
a += 1;
|
||||
a -= 1;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a){
|
||||
++a;
|
||||
--a;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
increment_decrement_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
a = a + 1;
|
||||
a = a - 1;
|
||||
a += 1;
|
||||
a -= 1;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a){
|
||||
++a;
|
||||
--a;
|
||||
++a;
|
||||
--a;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -944,7 +944,7 @@ collapse_vars_misc1: {
|
||||
function f5(x) { var z = foo(); return (5 - window.x) / z }
|
||||
function f6() { return window.a * window.z && zap() }
|
||||
function f7() { var b = window.a * window.z; return b + b }
|
||||
function f8() { var b = window.a * window.z; return b + (b + 5) }
|
||||
function f8() { var b = window.a * window.z; return b + (5 + b) }
|
||||
function f9() { var b = window.a * window.z; return bar() || b }
|
||||
function f10(x) { var a = 5; return a += 3; }
|
||||
function f11(x) { var a = 5; return a += 2; }
|
||||
@@ -3895,11 +3895,11 @@ issue_2436_10: {
|
||||
o = { b: 3 };
|
||||
return n;
|
||||
}
|
||||
console.log((c = o, [
|
||||
c.a,
|
||||
console.log([
|
||||
(c = o).a,
|
||||
f(c.b),
|
||||
c.b,
|
||||
]).join(" "));
|
||||
].join(" "));
|
||||
var c;
|
||||
}
|
||||
expect_stdout: "1 2 2"
|
||||
@@ -6121,3 +6121,39 @@ issue_3327: {
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
}
|
||||
|
||||
assign_left: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
(b = a, b.p).q = "PASS";
|
||||
return a.p.q;
|
||||
}({p: {}}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
(b = a).p.q = "PASS";
|
||||
return a.p.q;
|
||||
}({p: {}}));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
sub_property: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
return a[(b = a, b.length - 1)];
|
||||
}([ "FAIL", "PASS" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
return a[(b = a).length - 1];
|
||||
}([ "FAIL", "PASS" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -323,3 +323,25 @@ is_number_unsafe: {
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
is_boolean_var: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
for (var i = 0, c = !b; i < a.length; i++)
|
||||
if (!a[i] === c)
|
||||
return i;
|
||||
}([ false, true ], 42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
for (var i = 0, c = !b; i < a.length; i++)
|
||||
if (!a[i] == c)
|
||||
return i;
|
||||
}([ false, true ], 42));
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
@@ -1367,6 +1367,7 @@ cond_seq_assign_2: {
|
||||
|
||||
cond_seq_assign_3: {
|
||||
options = {
|
||||
assignments: true,
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
|
||||
@@ -1124,14 +1124,14 @@ issue_2207_1: {
|
||||
console.log(Math.max(3, 6, 2, 7, 3, 4));
|
||||
console.log(Math.cos(1.2345));
|
||||
console.log(Math.cos(1.2345) - Math.sin(4.321));
|
||||
console.log(Math.pow(Math.PI, Math.E - Math.LN10));
|
||||
console.log(Math.pow(Math.PI, Math.E - Math.LN10).toFixed(15));
|
||||
}
|
||||
expect: {
|
||||
console.log("A");
|
||||
console.log(7);
|
||||
console.log(Math.cos(1.2345));
|
||||
console.log(1.2543732512566947);
|
||||
console.log(1.6093984514472044);
|
||||
console.log("1.609398451447204");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -1540,7 +1540,7 @@ issue_2926_2: {
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_2968: {
|
||||
issue_2968_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
@@ -1571,6 +1571,39 @@ issue_2968: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2968_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
(function(a, b) {
|
||||
a <<= 0;
|
||||
a && (a[(c = "PASS", 0 >>> (b += 1))] = 0);
|
||||
})(42, -42);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
a = 42,
|
||||
((a <<= 0) && (a[(c = "PASS", 0)] = 0));
|
||||
var a;
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
truthy_conditionals: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -1610,3 +1643,47 @@ truthy_loops: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
if (console)
|
||||
return ++a;
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
if (console)
|
||||
return 1;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
try_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
return ++a;
|
||||
} catch (e) {}
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
return 1;
|
||||
} catch (e) {}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -358,6 +358,7 @@ inner_ref: {
|
||||
|
||||
issue_2107: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
@@ -387,6 +388,7 @@ issue_2107: {
|
||||
|
||||
issue_2114_1: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
@@ -419,6 +421,7 @@ issue_2114_1: {
|
||||
|
||||
issue_2114_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
@@ -1223,6 +1226,7 @@ issue_2630_1: {
|
||||
|
||||
issue_2630_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
@@ -1320,6 +1324,7 @@ issue_2630_4: {
|
||||
|
||||
issue_2630_5: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
@@ -1398,6 +1403,8 @@ recursive_inline_2: {
|
||||
issue_2657: {
|
||||
options = {
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
@@ -2467,6 +2474,7 @@ issue_3297_3: {
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
passes: 3,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
@@ -2505,18 +2513,18 @@ issue_3297_3: {
|
||||
}).processBulk([1, 2, 3]);
|
||||
}
|
||||
expect: {
|
||||
function function1(c) {
|
||||
function function1(u) {
|
||||
return {
|
||||
processBulk: function n(o) {
|
||||
var r, t, u = c();
|
||||
o && 0 < o.length && (r = {
|
||||
param1: o.shift(),
|
||||
processBulk: function n(r) {
|
||||
var o, t = u();
|
||||
r && 0 < r.length && (o = {
|
||||
param1: r.shift(),
|
||||
param2: {
|
||||
subparam1: u
|
||||
subparam1: t
|
||||
}
|
||||
}, t = function() {
|
||||
n(o);
|
||||
}, console.log(JSON.stringify(r)), t());
|
||||
},
|
||||
console.log(JSON.stringify(o)),
|
||||
n(r));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2530,3 +2538,477 @@ issue_3297_3: {
|
||||
'{"param1":3,"param2":{"subparam1":42}}',
|
||||
]
|
||||
}
|
||||
|
||||
cross_references_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log((function(factory) {
|
||||
return factory();
|
||||
})(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math);
|
||||
})(3));
|
||||
}
|
||||
expect: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math)(3));
|
||||
}
|
||||
expect_stdout: "9"
|
||||
}
|
||||
|
||||
cross_references_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
passes: 4,
|
||||
pure_getters: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log((function(factory) {
|
||||
return factory();
|
||||
})(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math);
|
||||
})(3));
|
||||
}
|
||||
expect: {
|
||||
console.log(9);
|
||||
}
|
||||
expect_stdout: "9"
|
||||
}
|
||||
|
||||
cross_references_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
},
|
||||
cube: function(n) {
|
||||
return n * n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(factory) {
|
||||
return factory();
|
||||
}(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
Math = {
|
||||
square: function(x) {
|
||||
return "(SQUARE" + x + ")";
|
||||
},
|
||||
cube: function(x) {
|
||||
return "(CUBE" + x + ")";
|
||||
}
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math);
|
||||
})(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
},
|
||||
cube: function(n) {
|
||||
return n * n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(Math) {
|
||||
return function(n) {
|
||||
Math = {
|
||||
square: function(x) {
|
||||
return "(SQUARE" + x + ")";
|
||||
},
|
||||
cube: function(x) {
|
||||
return "(CUBE" + x + ")";
|
||||
}
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math)(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect_stdout: [
|
||||
"(SQUARE2)(CUBE2)",
|
||||
"9 27",
|
||||
]
|
||||
}
|
||||
|
||||
loop_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(o) {
|
||||
function g(p) {
|
||||
return o[p];
|
||||
}
|
||||
function h(q) {
|
||||
while (g(q));
|
||||
}
|
||||
return h;
|
||||
}([ 1, "foo", 0 ])(2));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(o) {
|
||||
return function(q) {
|
||||
while (p = q, o[p]);
|
||||
var p;
|
||||
};
|
||||
}([ 1, "foo", 0 ])(2));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
functions: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function() {
|
||||
var a = function() {
|
||||
return "a";
|
||||
};
|
||||
var b = function x() {
|
||||
return !!x;
|
||||
};
|
||||
var c = function(c) {
|
||||
return c;
|
||||
};
|
||||
if (c(b(a()))) {
|
||||
var d = function() {};
|
||||
var e = function y() {
|
||||
return typeof y;
|
||||
};
|
||||
var f = function(f) {
|
||||
return f;
|
||||
};
|
||||
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
|
||||
}
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
var b = function x() {
|
||||
return !!x;
|
||||
};
|
||||
var c = function(c) {
|
||||
return c;
|
||||
};
|
||||
if (c(b(a()))) {
|
||||
function d() {}
|
||||
var e = function y() {
|
||||
return typeof y;
|
||||
};
|
||||
var f = function(f) {
|
||||
return f;
|
||||
};
|
||||
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
|
||||
}
|
||||
}();
|
||||
}
|
||||
expect_stdout: "a true 42 function function function"
|
||||
}
|
||||
|
||||
functions_use_strict: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
!function() {
|
||||
var a = function() {
|
||||
return "a";
|
||||
};
|
||||
var b = function x() {
|
||||
return !!x;
|
||||
};
|
||||
var c = function(c) {
|
||||
return c;
|
||||
};
|
||||
if (c(b(a()))) {
|
||||
var d = function() {};
|
||||
var e = function y() {
|
||||
return typeof y;
|
||||
};
|
||||
var f = function(f) {
|
||||
return f;
|
||||
};
|
||||
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
|
||||
}
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
!function() {
|
||||
function a() {
|
||||
return "a";
|
||||
}
|
||||
var b = function x() {
|
||||
return !!x;
|
||||
};
|
||||
var c = function(c) {
|
||||
return c;
|
||||
};
|
||||
if (c(b(a()))) {
|
||||
var d = function() {};
|
||||
var e = function y() {
|
||||
return typeof y;
|
||||
};
|
||||
var f = function(f) {
|
||||
return f;
|
||||
};
|
||||
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
|
||||
}
|
||||
}();
|
||||
}
|
||||
expect_stdout: "a true 42 function function function"
|
||||
}
|
||||
|
||||
issue_2437: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
functions: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function foo() {
|
||||
return bar();
|
||||
}
|
||||
function bar() {
|
||||
if (xhrDesc) {
|
||||
var req = new XMLHttpRequest();
|
||||
var result = !!req.onreadystatechange;
|
||||
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
|
||||
return result;
|
||||
} else {
|
||||
var req = new XMLHttpRequest();
|
||||
var detectFunc = function(){};
|
||||
req.onreadystatechange = detectFunc;
|
||||
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||
req.onreadystatechange = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
console.log(foo());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
if (xhrDesc) {
|
||||
var result = !!(req = new XMLHttpRequest()).onreadystatechange;
|
||||
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
|
||||
result;
|
||||
}
|
||||
function detectFunc() {}
|
||||
var req;
|
||||
(req = new XMLHttpRequest()).onreadystatechange = detectFunc;
|
||||
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||
return req.onreadystatechange = null, result;
|
||||
}());
|
||||
}
|
||||
}
|
||||
|
||||
issue_2485: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var foo = function(bar) {
|
||||
var n = function(a, b) {
|
||||
return a + b;
|
||||
};
|
||||
var sumAll = function(arg) {
|
||||
return arg.reduce(n, 0);
|
||||
};
|
||||
var runSumAll = function(arg) {
|
||||
return sumAll(arg);
|
||||
};
|
||||
bar.baz = function(arg) {
|
||||
var n = runSumAll(arg);
|
||||
return (n.get = 1), n;
|
||||
};
|
||||
return bar;
|
||||
};
|
||||
var bar = foo({});
|
||||
console.log(bar.baz([1, 2, 3]));
|
||||
}
|
||||
expect: {
|
||||
var foo = function(bar) {
|
||||
function n(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
function runSumAll(arg) {
|
||||
return function(arg) {
|
||||
return arg.reduce(n, 0);
|
||||
}(arg);
|
||||
}
|
||||
bar.baz = function(arg) {
|
||||
var n = runSumAll(arg);
|
||||
return (n.get = 1), n;
|
||||
};
|
||||
return bar;
|
||||
};
|
||||
var bar = foo({});
|
||||
console.log(bar.baz([1, 2, 3]));
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
issue_3364: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
var s = 2, a = 100, b = 10, c = 0;
|
||||
function f(p, e, r) {
|
||||
try {
|
||||
for (var i = 1; i-- > 0;)
|
||||
var a = function(x) {
|
||||
function g(y) {
|
||||
y && y[a++];
|
||||
}
|
||||
var x = g(--s >= 0 && f(c++));
|
||||
for (var j = 1; --j > 0;);
|
||||
}();
|
||||
} catch (e) {
|
||||
try {
|
||||
return;
|
||||
} catch (z) {
|
||||
for (var k = 1; --k > 0;) {
|
||||
for (var l = 1; l > 0; --l) {
|
||||
var n = function() {};
|
||||
for (var k in n)
|
||||
var o = (n, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var r = f();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var s = 2, c = 0;
|
||||
(function n(r, o, a) {
|
||||
try {
|
||||
for (var f = 1; f-- >0;)
|
||||
var t = function(r) {
|
||||
(function(r) {
|
||||
r && r[t++];
|
||||
})(--s >= 0 && n(c++));
|
||||
for (var o = 1; --o > 0;);
|
||||
}();
|
||||
} catch (o) {
|
||||
try {
|
||||
return;
|
||||
} catch (r) {
|
||||
for (var v = 1; --v > 0;)
|
||||
for (var i = 1; i > 0;--i) {
|
||||
function u() {}
|
||||
for (var v in u);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_3366: {
|
||||
options = {
|
||||
functions: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {
|
||||
return function() {};
|
||||
}
|
||||
var a = g();
|
||||
(function() {
|
||||
this && a && console.log("PASS");
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
function a() {}
|
||||
(function() {
|
||||
this && a && console.log("PASS");
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -861,3 +861,111 @@ issue_3215_4: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3355_1: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect: {
|
||||
(function o() {
|
||||
var o;
|
||||
})();
|
||||
(function o() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_3355_2: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_3355_3: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var b = function c() {
|
||||
var c = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var o = function a() {
|
||||
var a = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3355_4: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var b = function c() {
|
||||
var c = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var o = function n() {
|
||||
var n = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -6716,3 +6716,24 @@ issue_3297: {
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
drop_side_effect_free: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 123;
|
||||
"" + (a && (a.b = 0) || a);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 123;
|
||||
a.b = 0;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
@@ -924,14 +924,14 @@ call: {
|
||||
b.c = function() {
|
||||
console.log(this === b ? "bar" : "baz");
|
||||
},
|
||||
a, b(),
|
||||
b(),
|
||||
(a, b.c)(),
|
||||
a, function() {
|
||||
function() {
|
||||
console.log(this === a);
|
||||
}(),
|
||||
a, new b(),
|
||||
a, new b.c(),
|
||||
a, new function() {
|
||||
new b(),
|
||||
new b.c(),
|
||||
new function() {
|
||||
console.log(this === a);
|
||||
}();
|
||||
}
|
||||
@@ -944,3 +944,23 @@ call: {
|
||||
"false",
|
||||
]
|
||||
}
|
||||
|
||||
missing_link: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100;
|
||||
a;
|
||||
a++ + (0 ? 2 : 1);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 100;
|
||||
a,
|
||||
a++,
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
exports["base54"] = base54;
|
||||
exports["Compressor"] = Compressor;
|
||||
exports["defaults"] = defaults;
|
||||
exports["is_identifier"] = is_identifier;
|
||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||
exports["mangle_properties"] = mangle_properties;
|
||||
exports["minify"] = minify;
|
||||
@@ -9,7 +7,6 @@ exports["OutputStream"] = OutputStream;
|
||||
exports["parse"] = parse;
|
||||
exports["push_uniq"] = push_uniq;
|
||||
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||
exports["SourceMap"] = SourceMap;
|
||||
exports["string_template"] = string_template;
|
||||
exports["tokenizer"] = tokenizer;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var site = "https://browserbench.org/JetStream";
|
||||
var site = "https://browserbench.org/JetStream1.1";
|
||||
if (typeof phantom == "undefined") {
|
||||
require("../tools/exit");
|
||||
var args = process.argv.slice(2);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
var fs = require("fs");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
|
||||
function read(path) {
|
||||
return fs.readFileSync(path, "utf8");
|
||||
@@ -714,4 +715,32 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should compress swarm of unused variables with reasonable performance", function(done) {
|
||||
var code = [
|
||||
"console.log(function() {",
|
||||
];
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
code.push("var obj" + i + " = {p: " + i + "};");
|
||||
}
|
||||
code.push("var map = {");
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
code.push("obj" + i + ": obj" + i + ",");
|
||||
}
|
||||
code = code.concat([
|
||||
"};",
|
||||
"return obj25.p + obj121.p + obj1024.p;",
|
||||
"}());",
|
||||
]).join("\n");
|
||||
exec(uglifyjscmd + " -mc", function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, [
|
||||
"console.log(function(){",
|
||||
"var p={p:25},n={p:121},o={p:1024};",
|
||||
"return p.p+n.p+o.p",
|
||||
"}());\n",
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(stdout), run_code(code));
|
||||
done();
|
||||
}).stdin.end(code);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,8 +73,10 @@ exports.run_code = function(code, reuse) {
|
||||
process.stdout.write = original_write;
|
||||
if (!reuse || code.indexOf(".prototype") >= 0) {
|
||||
context = null;
|
||||
} else for (var key in context) {
|
||||
delete context[key];
|
||||
} else {
|
||||
vm.runInContext(Object.keys(context).map(function(name) {
|
||||
return "delete " + name;
|
||||
}).join("\n"), context);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user