Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
- `arguments` (default: `true`) -- replace `arguments[index]` with function
|
||||||
parameter name whenever possible.
|
parameter name whenever possible.
|
||||||
|
|
||||||
|
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
|
||||||
|
|
||||||
- `booleans` (default: `true`) -- various optimizations for boolean context,
|
- `booleans` (default: `true`) -- various optimizations for boolean context,
|
||||||
for example `!!a ? b : c → a ? b : c`
|
for example `!!a ? b : c → a ? b : c`
|
||||||
|
|
||||||
|
|||||||
210
lib/compress.js
210
lib/compress.js
@@ -49,6 +49,7 @@ function Compressor(options, false_by_default) {
|
|||||||
TreeTransformer.call(this, this.before, this.after);
|
TreeTransformer.call(this, this.before, this.after);
|
||||||
this.options = defaults(options, {
|
this.options = defaults(options, {
|
||||||
arguments : !false_by_default,
|
arguments : !false_by_default,
|
||||||
|
assignments : !false_by_default,
|
||||||
booleans : !false_by_default,
|
booleans : !false_by_default,
|
||||||
collapse_vars : !false_by_default,
|
collapse_vars : !false_by_default,
|
||||||
comparisons : !false_by_default,
|
comparisons : !false_by_default,
|
||||||
@@ -537,13 +538,11 @@ merge(Compressor.prototype, {
|
|||||||
var d = sym.definition();
|
var d = sym.definition();
|
||||||
var safe = safe_to_assign(tw, d, sym.scope, node.right);
|
var safe = safe_to_assign(tw, d, sym.scope, node.right);
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
if (!safe) return;
|
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
if (!fixed && node.operator != "=") return;
|
if (!fixed && node.operator != "=") return;
|
||||||
var eq = node.operator == "=";
|
var eq = node.operator == "=";
|
||||||
var value = eq ? node.right : node;
|
var value = eq ? node.right : node;
|
||||||
if (is_modified(compressor, tw, node, value, 0)) return;
|
if (is_modified(compressor, tw, node, value, 0)) return;
|
||||||
d.references.push(sym);
|
|
||||||
if (!eq) d.chained = true;
|
if (!eq) d.chained = true;
|
||||||
d.fixed = eq ? function() {
|
d.fixed = eq ? function() {
|
||||||
return node.right;
|
return node.right;
|
||||||
@@ -554,6 +553,8 @@ merge(Compressor.prototype, {
|
|||||||
right: node.right
|
right: node.right
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
if (!safe) return;
|
||||||
|
d.references.push(sym);
|
||||||
mark(tw, d, false);
|
mark(tw, d, false);
|
||||||
node.right.walk(tw);
|
node.right.walk(tw);
|
||||||
mark(tw, d, true);
|
mark(tw, d, true);
|
||||||
@@ -783,10 +784,8 @@ merge(Compressor.prototype, {
|
|||||||
var d = exp.definition();
|
var d = exp.definition();
|
||||||
var safe = safe_to_assign(tw, d, exp.scope, true);
|
var safe = safe_to_assign(tw, d, exp.scope, true);
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
if (!safe) return;
|
|
||||||
var fixed = d.fixed;
|
var fixed = d.fixed;
|
||||||
if (!fixed) return;
|
if (!fixed) return;
|
||||||
d.references.push(exp);
|
|
||||||
d.chained = true;
|
d.chained = true;
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return make_node(AST_Binary, node, {
|
return make_node(AST_Binary, node, {
|
||||||
@@ -800,6 +799,8 @@ merge(Compressor.prototype, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
if (!safe) return;
|
||||||
|
d.references.push(exp);
|
||||||
mark(tw, d, true);
|
mark(tw, d, true);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -1100,10 +1101,10 @@ merge(Compressor.prototype, {
|
|||||||
stop_if_hit = parent;
|
stop_if_hit = parent;
|
||||||
}
|
}
|
||||||
// Replace variable with assignment when found
|
// Replace variable with assignment when found
|
||||||
var hit_lhs, hit_rhs;
|
var hit_rhs;
|
||||||
if (can_replace
|
if (can_replace
|
||||||
&& !(node instanceof AST_SymbolDeclaration)
|
&& !(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)))) {
|
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
||||||
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||||
abort = true;
|
abort = true;
|
||||||
@@ -1193,10 +1194,9 @@ merge(Compressor.prototype, {
|
|||||||
var stop_after = null;
|
var stop_after = null;
|
||||||
var stop_if_hit = null;
|
var stop_if_hit = null;
|
||||||
var lhs = get_lhs(candidate);
|
var lhs = get_lhs(candidate);
|
||||||
var rhs = get_rhs(candidate);
|
|
||||||
var side_effects = lhs && lhs.has_side_effects(compressor);
|
var side_effects = lhs && lhs.has_side_effects(compressor);
|
||||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs);
|
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;
|
if (!scan_lhs && !scan_rhs) continue;
|
||||||
// Locate symbols which may execute code outside of scanning range
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
@@ -1523,6 +1523,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function foldable(expr) {
|
function foldable(expr) {
|
||||||
|
if (!expr) return false;
|
||||||
if (expr instanceof AST_SymbolRef) {
|
if (expr instanceof AST_SymbolRef) {
|
||||||
var value = expr.evaluate(compressor);
|
var value = expr.evaluate(compressor);
|
||||||
if (value === expr) return rhs_exact_match;
|
if (value === expr) return rhs_exact_match;
|
||||||
@@ -1544,10 +1545,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
return !circular && rhs_exact_match;
|
return !circular && rhs_exact_match;
|
||||||
}
|
|
||||||
|
|
||||||
function rhs_exact_match(node) {
|
function rhs_exact_match(node) {
|
||||||
return rhs.equivalent_to(node);
|
return expr.equivalent_to(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function rhs_fuzzy_match(value, fallback) {
|
function rhs_fuzzy_match(value, fallback) {
|
||||||
@@ -2251,45 +2252,38 @@ merge(Compressor.prototype, {
|
|||||||
return !compressor.option("pure_getters")
|
return !compressor.option("pure_getters")
|
||||||
|| this._dot_throw(compressor);
|
|| this._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_strict(compressor) {
|
function is_strict(compressor) {
|
||||||
return /strict/.test(compressor.option("pure_getters"));
|
return /strict/.test(compressor.option("pure_getters"));
|
||||||
}
|
}
|
||||||
|
|
||||||
def(AST_Node, is_strict);
|
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_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) {
|
def(AST_Assign, function(compressor) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
&& this.right._dot_throw(compressor);
|
&& 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) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return this.consequent._dot_throw(compressor)
|
return this.consequent._dot_throw(compressor)
|
||||||
|| this.alternative._dot_throw(compressor);
|
|| this.alternative._dot_throw(compressor);
|
||||||
})
|
})
|
||||||
|
def(AST_Constant, return_false);
|
||||||
def(AST_Dot, function(compressor) {
|
def(AST_Dot, function(compressor) {
|
||||||
if (!is_strict(compressor)) return false;
|
if (!is_strict(compressor)) return false;
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
||||||
return !(exp instanceof AST_Lambda && this.property == "prototype");
|
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) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node()._dot_throw(compressor);
|
return this.tail_node()._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
@@ -2301,6 +2295,11 @@ merge(Compressor.prototype, {
|
|||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._dot_throw(compressor);
|
return !fixed || fixed._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
|
def(AST_UnaryPrefix, function() {
|
||||||
|
return this.operator == "void";
|
||||||
|
});
|
||||||
|
def(AST_UnaryPostfix, return_false);
|
||||||
|
def(AST_Undefined, return_true);
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("_dot_throw", func);
|
node.DEFMETHOD("_dot_throw", func);
|
||||||
});
|
});
|
||||||
@@ -2334,6 +2333,10 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node().is_boolean(compressor);
|
return this.tail_node().is_boolean(compressor);
|
||||||
});
|
});
|
||||||
|
def(AST_SymbolRef, function(compressor) {
|
||||||
|
var fixed = this.fixed_value();
|
||||||
|
return fixed && fixed.is_boolean(compressor);
|
||||||
|
});
|
||||||
var unary = makePredicate("! delete");
|
var unary = makePredicate("! delete");
|
||||||
def(AST_UnaryPrefix, function() {
|
def(AST_UnaryPrefix, function() {
|
||||||
return unary[this.operator];
|
return unary[this.operator];
|
||||||
@@ -2415,6 +2418,10 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node().is_number(compressor);
|
return this.tail_node().is_number(compressor);
|
||||||
});
|
});
|
||||||
|
def(AST_SymbolRef, function(compressor) {
|
||||||
|
var fixed = this.fixed_value();
|
||||||
|
return fixed && fixed.is_number(compressor);
|
||||||
|
});
|
||||||
var unary = makePredicate("+ - ~ ++ --");
|
var unary = makePredicate("+ - ~ ++ --");
|
||||||
def(AST_Unary, function() {
|
def(AST_Unary, function() {
|
||||||
return unary[this.operator];
|
return unary[this.operator];
|
||||||
@@ -2426,22 +2433,26 @@ merge(Compressor.prototype, {
|
|||||||
// methods to determine if an expression has a string result type
|
// methods to determine if an expression has a string result type
|
||||||
(function(def) {
|
(function(def) {
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_String, return_true);
|
def(AST_Assign, function(compressor) {
|
||||||
def(AST_UnaryPrefix, function() {
|
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||||
return this.operator == "typeof";
|
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor) {
|
def(AST_Binary, function(compressor) {
|
||||||
return this.operator == "+" &&
|
return this.operator == "+" &&
|
||||||
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
||||||
});
|
});
|
||||||
def(AST_Assign, function(compressor) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node().is_string(compressor);
|
return this.tail_node().is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor) {
|
def(AST_String, return_true);
|
||||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
def(AST_SymbolRef, function(compressor) {
|
||||||
|
var fixed = this.fixed_value();
|
||||||
|
return fixed && fixed.is_string(compressor);
|
||||||
|
});
|
||||||
|
def(AST_UnaryPrefix, function() {
|
||||||
|
return this.operator == "typeof";
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("is_string", func);
|
node.DEFMETHOD("is_string", func);
|
||||||
@@ -3240,6 +3251,12 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
def(AST_Node, return_false);
|
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_Constant, return_true);
|
||||||
def(AST_Lambda, function(scope) {
|
def(AST_Lambda, function(scope) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -3268,21 +3285,15 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
return result;
|
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() {
|
def(AST_Object, function() {
|
||||||
return all(this.properties);
|
return all(this.properties);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function() {
|
def(AST_ObjectProperty, function() {
|
||||||
return this.value.is_constant_expression();
|
return this.value.is_constant_expression();
|
||||||
});
|
});
|
||||||
|
def(AST_Unary, function() {
|
||||||
|
return this.expression.is_constant_expression();
|
||||||
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("is_constant_expression", func);
|
node.DEFMETHOD("is_constant_expression", func);
|
||||||
});
|
});
|
||||||
@@ -3992,17 +4003,17 @@ merge(Compressor.prototype, {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor, first_in_statement) {
|
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 (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (lazy_op[this.operator]) {
|
if (lazy_op[this.operator]) {
|
||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
node.right = right;
|
node.right = right.drop_side_effect_free(compressor);
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
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);
|
if (!left) return right;
|
||||||
return make_sequence(this, [ left, right ]);
|
return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, first_in_statement) {
|
def(AST_Call, function(compressor, first_in_statement) {
|
||||||
@@ -4062,19 +4073,6 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Function, function(compressor) {
|
def(AST_Function, function(compressor) {
|
||||||
return this.name && compressor.option("ie8") ? this : null;
|
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) {
|
def(AST_Object, function(compressor, first_in_statement) {
|
||||||
var values = trim(this.properties, compressor, first_in_statement);
|
var values = trim(this.properties, compressor, first_in_statement);
|
||||||
return values && make_sequence(this, values);
|
return values && make_sequence(this, values);
|
||||||
@@ -4082,12 +4080,10 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_ObjectProperty, function(compressor, first_in_statement) {
|
def(AST_ObjectProperty, function(compressor, first_in_statement) {
|
||||||
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor, first_in_statement) {
|
||||||
var last = this.tail_node();
|
var expressions = trim(this.expressions, compressor, first_in_statement);
|
||||||
var expr = last.drop_side_effect_free(compressor);
|
if (expressions === this.expressions) return this;
|
||||||
if (expr === last) return this;
|
if (!expressions) return null;
|
||||||
var expressions = this.expressions.slice(0, -1);
|
|
||||||
if (expr) expressions.push(expr);
|
|
||||||
return make_sequence(this, expressions);
|
return make_sequence(this, expressions);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor, first_in_statement) {
|
def(AST_Sub, function(compressor, first_in_statement) {
|
||||||
@@ -4099,9 +4095,27 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(this, [ expression, property ]);
|
return make_sequence(this, [ expression, property ]);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
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_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) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("drop_side_effect_free", func);
|
node.DEFMETHOD("drop_side_effect_free", func);
|
||||||
});
|
});
|
||||||
@@ -4596,9 +4610,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Definitions, function(self, compressor) {
|
OPT(AST_Definitions, function(self, compressor) {
|
||||||
if (self.definitions.length == 0)
|
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
||||||
return make_node(AST_EmptyStatement, self);
|
|
||||||
return self;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Call.DEFMETHOD("lift_sequences", function(compressor) {
|
AST_Call.DEFMETHOD("lift_sequences", function(compressor) {
|
||||||
@@ -4652,12 +4664,30 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
if (self.args.length != 1) {
|
if (self.args.length == 1) {
|
||||||
return make_node(AST_Array, self, {
|
var first = self.args[0];
|
||||||
elements: self.args
|
if (first instanceof AST_Number) try {
|
||||||
}).optimize(compressor);
|
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":
|
case "Object":
|
||||||
if (self.args.length == 0) {
|
if (self.args.length == 0) {
|
||||||
return make_node(AST_Object, self, {
|
return make_node(AST_Object, self, {
|
||||||
@@ -5005,8 +5035,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function can_inject_vars(catches, safe_to_inject) {
|
function can_inject_vars(catches, safe_to_inject) {
|
||||||
var len = fn.body.length;
|
for (var i = 0, len = fn.body.length; i < len; i++) {
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
var stat = fn.body[i];
|
var stat = fn.body[i];
|
||||||
if (!(stat instanceof AST_Var)) continue;
|
if (!(stat instanceof AST_Var)) continue;
|
||||||
if (!safe_to_inject) return false;
|
if (!safe_to_inject) return false;
|
||||||
@@ -5035,7 +5064,8 @@ merge(Compressor.prototype, {
|
|||||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||||
}
|
}
|
||||||
} while (!(scope instanceof AST_Scope));
|
} 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)
|
||||||
|
&& fn.parent_scope === compressor.find_parent(AST_Scope);
|
||||||
var inline = compressor.option("inline");
|
var inline = compressor.option("inline");
|
||||||
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||||
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||||
@@ -5844,6 +5874,7 @@ merge(Compressor.prototype, {
|
|||||||
value = fixed.optimize(compressor);
|
value = fixed.optimize(compressor);
|
||||||
if (value === fixed) value = fixed.clone(true);
|
if (value === fixed) value = fixed.clone(true);
|
||||||
}
|
}
|
||||||
|
def.replaced++;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if (fixed && def.should_replace === undefined) {
|
if (fixed && def.should_replace === undefined) {
|
||||||
@@ -5886,7 +5917,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def.should_replace) {
|
if (def.should_replace) {
|
||||||
return def.should_replace();
|
var value = def.should_replace();
|
||||||
|
def.replaced++;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -6010,6 +6043,7 @@ merge(Compressor.prototype, {
|
|||||||
|| parent instanceof AST_Sequence && parent.tail_node() === node);
|
|| parent instanceof AST_Sequence && parent.tail_node() === node);
|
||||||
}
|
}
|
||||||
self = self.lift_sequences(compressor);
|
self = self.lift_sequences(compressor);
|
||||||
|
if (!compressor.option("assignments")) return self;
|
||||||
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||||
// x = expr1 OP expr2
|
// x = expr1 OP expr2
|
||||||
if (self.right.left instanceof AST_SymbolRef
|
if (self.right.left instanceof AST_SymbolRef
|
||||||
@@ -6028,6 +6062,16 @@ merge(Compressor.prototype, {
|
|||||||
self.right = self.right.left;
|
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;
|
return self;
|
||||||
|
|
||||||
function in_try(level, node) {
|
function in_try(level, node) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.4.10",
|
"version": "3.5.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -239,3 +239,113 @@ index_length: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1 2"
|
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: {
|
asm_mixed: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
booleans: true,
|
booleans: true,
|
||||||
comparisons: true,
|
comparisons: true,
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
op_equals_left_local_var: {
|
op_equals_left_local_var: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -60,6 +61,7 @@ op_equals_left_local_var: {
|
|||||||
|
|
||||||
op_equals_right_local_var: {
|
op_equals_right_local_var: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -123,6 +125,7 @@ op_equals_right_local_var: {
|
|||||||
}
|
}
|
||||||
op_equals_left_global_var: {
|
op_equals_left_global_var: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -179,6 +182,7 @@ op_equals_left_global_var: {
|
|||||||
|
|
||||||
op_equals_right_global_var: {
|
op_equals_right_global_var: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -236,3 +240,52 @@ op_equals_right_global_var: {
|
|||||||
x = g() & x;
|
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 f5(x) { var z = foo(); return (5 - window.x) / z }
|
||||||
function f6() { return window.a * window.z && zap() }
|
function f6() { return window.a * window.z && zap() }
|
||||||
function f7() { var b = window.a * window.z; return b + b }
|
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 f9() { var b = window.a * window.z; return bar() || b }
|
||||||
function f10(x) { var a = 5; return a += 3; }
|
function f10(x) { var a = 5; return a += 3; }
|
||||||
function f11(x) { var a = 5; return a += 2; }
|
function f11(x) { var a = 5; return a += 2; }
|
||||||
|
|||||||
@@ -323,3 +323,25 @@ is_number_unsafe: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
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: {
|
cond_seq_assign_3: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -1540,7 +1540,7 @@ issue_2926_2: {
|
|||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_2968: {
|
issue_2968_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
@@ -1571,6 +1571,39 @@ issue_2968: {
|
|||||||
expect_stdout: "PASS"
|
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: {
|
truthy_conditionals: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
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: {
|
issue_2107: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 3,
|
||||||
@@ -387,6 +388,7 @@ issue_2107: {
|
|||||||
|
|
||||||
issue_2114_1: {
|
issue_2114_1: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
@@ -419,6 +421,7 @@ issue_2114_1: {
|
|||||||
|
|
||||||
issue_2114_2: {
|
issue_2114_2: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
@@ -1223,6 +1226,7 @@ issue_2630_1: {
|
|||||||
|
|
||||||
issue_2630_2: {
|
issue_2630_2: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 2,
|
passes: 2,
|
||||||
@@ -1320,6 +1324,7 @@ issue_2630_4: {
|
|||||||
|
|
||||||
issue_2630_5: {
|
issue_2630_5: {
|
||||||
options = {
|
options = {
|
||||||
|
assignments: true,
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -1398,6 +1403,8 @@ recursive_inline_2: {
|
|||||||
issue_2657: {
|
issue_2657: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
sequences: true,
|
sequences: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -2467,6 +2474,7 @@ issue_3297_3: {
|
|||||||
inline: true,
|
inline: true,
|
||||||
join_vars: true,
|
join_vars: true,
|
||||||
passes: 3,
|
passes: 3,
|
||||||
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
sequences: true,
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -2505,18 +2513,18 @@ issue_3297_3: {
|
|||||||
}).processBulk([1, 2, 3]);
|
}).processBulk([1, 2, 3]);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function function1(c) {
|
function function1(u) {
|
||||||
return {
|
return {
|
||||||
processBulk: function n(o) {
|
processBulk: function n(r) {
|
||||||
var r, t, u = c();
|
var o, t = u();
|
||||||
o && 0 < o.length && (r = {
|
r && 0 < r.length && (o = {
|
||||||
param1: o.shift(),
|
param1: r.shift(),
|
||||||
param2: {
|
param2: {
|
||||||
subparam1: u
|
subparam1: t
|
||||||
}
|
}
|
||||||
}, t = function() {
|
},
|
||||||
n(o);
|
console.log(JSON.stringify(o)),
|
||||||
}, console.log(JSON.stringify(r)), t());
|
n(r));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2530,3 +2538,140 @@ issue_3297_3: {
|
|||||||
'{"param1":3,"param2":{"subparam1":42}}',
|
'{"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",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -6716,3 +6716,24 @@ issue_3297: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
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() {
|
b.c = function() {
|
||||||
console.log(this === b ? "bar" : "baz");
|
console.log(this === b ? "bar" : "baz");
|
||||||
},
|
},
|
||||||
a, b(),
|
b(),
|
||||||
(a, b.c)(),
|
(a, b.c)(),
|
||||||
a, function() {
|
function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
}(),
|
}(),
|
||||||
a, new b(),
|
new b(),
|
||||||
a, new b.c(),
|
new b.c(),
|
||||||
a, new function() {
|
new function() {
|
||||||
console.log(this === a);
|
console.log(this === a);
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
@@ -944,3 +944,23 @@ call: {
|
|||||||
"false",
|
"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,6 +1,7 @@
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var exec = require("child_process").exec;
|
var exec = require("child_process").exec;
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
|
var run_code = require("../sandbox").run_code;
|
||||||
|
|
||||||
function read(path) {
|
function read(path) {
|
||||||
return fs.readFileSync(path, "utf8");
|
return fs.readFileSync(path, "utf8");
|
||||||
@@ -714,4 +715,32 @@ describe("bin/uglifyjs", function() {
|
|||||||
done();
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user