Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34075fc4c4 | ||
|
|
e5436ca566 | ||
|
|
cfde686eab | ||
|
|
a206964c0a | ||
|
|
c56d89f804 | ||
|
|
c215706350 | ||
|
|
d3b93ec682 | ||
|
|
6fe20dbe33 |
242
lib/compress.js
242
lib/compress.js
@@ -2296,17 +2296,14 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Node, is_strict);
|
def(AST_Node, is_strict);
|
||||||
def(AST_Array, return_false);
|
def(AST_Array, return_false);
|
||||||
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) {
|
def(AST_Binary, function(compressor) {
|
||||||
return (this.operator == "&&" || this.operator == "||")
|
return lazy_op[this.operator] && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||||
&& (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_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;
|
||||||
@@ -2346,6 +2343,51 @@ merge(Compressor.prototype, {
|
|||||||
node.DEFMETHOD("_dot_throw", func);
|
node.DEFMETHOD("_dot_throw", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(function(def) {
|
||||||
|
def(AST_Node, return_false);
|
||||||
|
def(AST_Array, return_true);
|
||||||
|
def(AST_Assign, function(compressor) {
|
||||||
|
return this.operator != "=" || this.right.is_defined(compressor);
|
||||||
|
});
|
||||||
|
def(AST_Binary, function(compressor) {
|
||||||
|
switch (this.operator) {
|
||||||
|
case "&&":
|
||||||
|
return this.left.is_defined(compressor) && this.right.is_defined(compressor);
|
||||||
|
case "||":
|
||||||
|
return this.left.is_defined(compressor) || this.right.is_defined(compressor);
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
def(AST_Conditional, function(compressor) {
|
||||||
|
return this.consequent.is_defined(compressor) && this.alternative.is_defined(compressor);
|
||||||
|
});
|
||||||
|
def(AST_Constant, return_true);
|
||||||
|
def(AST_Lambda, return_true);
|
||||||
|
def(AST_Object, return_true);
|
||||||
|
def(AST_Sequence, function(compressor) {
|
||||||
|
return this.tail_node().is_defined(compressor);
|
||||||
|
});
|
||||||
|
def(AST_SymbolRef, function(compressor) {
|
||||||
|
if (this.is_undefined) return false;
|
||||||
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return true;
|
||||||
|
if (this.is_immutable()) return true;
|
||||||
|
var fixed = this.fixed_value();
|
||||||
|
if (!fixed) return false;
|
||||||
|
this.is_defined = return_true;
|
||||||
|
var result = fixed.is_defined(compressor);
|
||||||
|
delete this.is_defined;
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
def(AST_UnaryPrefix, function() {
|
||||||
|
return this.operator != "void";
|
||||||
|
});
|
||||||
|
def(AST_UnaryPostfix, return_true);
|
||||||
|
def(AST_Undefined, return_false);
|
||||||
|
})(function(node, func) {
|
||||||
|
node.DEFMETHOD("is_defined", func);
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
|
|
||||||
// methods to determine whether an expression has a boolean result type
|
// methods to determine whether an expression has a boolean result type
|
||||||
@@ -2490,6 +2532,20 @@ merge(Compressor.prototype, {
|
|||||||
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));
|
||||||
});
|
});
|
||||||
|
var fn = makePredicate([
|
||||||
|
"charAt",
|
||||||
|
"substr",
|
||||||
|
"substring",
|
||||||
|
"toLowerCase",
|
||||||
|
"toString",
|
||||||
|
"toUpperCase",
|
||||||
|
"trim",
|
||||||
|
]);
|
||||||
|
def(AST_Call, function(compressor) {
|
||||||
|
if (!compressor.option("unsafe")) return false;
|
||||||
|
var exp = this.expression;
|
||||||
|
return exp instanceof AST_Dot && fn[exp.property];
|
||||||
|
});
|
||||||
def(AST_Conditional, function(compressor) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||||
});
|
});
|
||||||
@@ -2497,6 +2553,9 @@ merge(Compressor.prototype, {
|
|||||||
return this.tail_node().is_string(compressor);
|
return this.tail_node().is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_String, return_true);
|
def(AST_String, return_true);
|
||||||
|
def(AST_Sub, function(compressor) {
|
||||||
|
return this.expression.is_string(compressor) && this.property instanceof AST_Number;
|
||||||
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
if (!fixed) return false;
|
if (!fixed) return false;
|
||||||
@@ -2976,6 +3035,7 @@ merge(Compressor.prototype, {
|
|||||||
if (arg === value) return this;
|
if (arg === value) return this;
|
||||||
args.push(value);
|
args.push(value);
|
||||||
}
|
}
|
||||||
|
if (key == "replace" && typeof args[1] == "function") return this;
|
||||||
try {
|
try {
|
||||||
return val[key].apply(val, args);
|
return val[key].apply(val, args);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
@@ -3084,24 +3144,31 @@ merge(Compressor.prototype, {
|
|||||||
return this.pure || !compressor.pure_funcs(this);
|
return this.pure || !compressor.pure_funcs(this);
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
||||||
AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
|
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
||||||
if (!compressor.option("unsafe")) return;
|
if (!compressor.option("unsafe")) return false;
|
||||||
var expr = this.expression;
|
var dot = this.expression;
|
||||||
|
if (!(dot instanceof AST_Dot)) return false;
|
||||||
|
var exp = dot.expression;
|
||||||
var map;
|
var map;
|
||||||
if (expr instanceof AST_Array) {
|
var prop = dot.property;
|
||||||
|
if (exp instanceof AST_Array) {
|
||||||
map = native_fns.Array;
|
map = native_fns.Array;
|
||||||
} else if (expr.is_boolean(compressor)) {
|
} else if (exp.is_boolean(compressor)) {
|
||||||
map = native_fns.Boolean;
|
map = native_fns.Boolean;
|
||||||
} else if (expr.is_number(compressor)) {
|
} else if (exp.is_number(compressor)) {
|
||||||
map = native_fns.Number;
|
map = native_fns.Number;
|
||||||
} else if (expr instanceof AST_RegExp) {
|
} else if (exp instanceof AST_RegExp) {
|
||||||
map = native_fns.RegExp;
|
map = native_fns.RegExp;
|
||||||
} else if (expr.is_string(compressor)) {
|
} else if (exp.is_string(compressor)) {
|
||||||
map = native_fns.String;
|
map = native_fns.String;
|
||||||
} else if (!this.may_throw_on_access(compressor)) {
|
if (prop == "replace") {
|
||||||
|
var arg = this.args[1];
|
||||||
|
if (arg && !arg.is_string(compressor)) return false;
|
||||||
|
}
|
||||||
|
} else if (!dot.may_throw_on_access(compressor)) {
|
||||||
map = native_fns.Object;
|
map = native_fns.Object;
|
||||||
}
|
}
|
||||||
return map && map[this.property];
|
return map && map[prop];
|
||||||
});
|
});
|
||||||
|
|
||||||
// determine if expression has side effects
|
// determine if expression has side effects
|
||||||
@@ -3126,8 +3193,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Call, function(compressor) {
|
def(AST_Call, function(compressor) {
|
||||||
if (!this.is_expr_pure(compressor)
|
if (!this.is_expr_pure(compressor)
|
||||||
&& (!this.expression.is_call_pure(compressor)
|
&& (!this.is_call_pure(compressor) || this.expression.has_side_effects(compressor))) {
|
||||||
|| this.expression.has_side_effects(compressor))) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return any(this.args, compressor);
|
return any(this.args, compressor);
|
||||||
@@ -4106,10 +4172,16 @@ merge(Compressor.prototype, {
|
|||||||
var right = this.right.drop_side_effect_free(compressor, first_in_statement);
|
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;
|
var node = this;
|
||||||
var node = this.clone();
|
if (right !== node.right) {
|
||||||
node.right = right.drop_side_effect_free(compressor);
|
node = this.clone();
|
||||||
return node;
|
node.right = right.drop_side_effect_free(compressor);
|
||||||
|
}
|
||||||
|
return (first_in_statement ? best_of_statement : best_of_expression)(node, make_node(AST_Binary, this, {
|
||||||
|
operator: node.operator == "&&" ? "||" : "&&",
|
||||||
|
left: node.left.negate(compressor, first_in_statement),
|
||||||
|
right: node.right
|
||||||
|
}));
|
||||||
} 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 right;
|
if (!left) return right;
|
||||||
@@ -4118,16 +4190,15 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, first_in_statement) {
|
def(AST_Call, function(compressor, first_in_statement) {
|
||||||
if (!this.is_expr_pure(compressor)) {
|
if (!this.is_expr_pure(compressor)) {
|
||||||
if (this.expression.is_call_pure(compressor)) {
|
var exp = this.expression;
|
||||||
|
if (this.is_call_pure(compressor)) {
|
||||||
var exprs = this.args.slice();
|
var exprs = this.args.slice();
|
||||||
exprs.unshift(this.expression.expression);
|
exprs.unshift(exp.expression);
|
||||||
exprs = trim(exprs, compressor, first_in_statement);
|
exprs = trim(exprs, compressor, first_in_statement);
|
||||||
return exprs && make_sequence(this, exprs);
|
return exprs && make_sequence(this, exprs);
|
||||||
}
|
}
|
||||||
if (this.expression instanceof AST_Function
|
if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
|
||||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
var exp = node.expression;
|
|
||||||
exp.process_expression(false, compressor);
|
exp.process_expression(false, compressor);
|
||||||
exp.walk(new TreeWalker(function(node) {
|
exp.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Return && node.value) {
|
if (node instanceof AST_Return && node.value) {
|
||||||
@@ -4486,14 +4557,14 @@ merge(Compressor.prototype, {
|
|||||||
operator : "||",
|
operator : "||",
|
||||||
left : negated,
|
left : negated,
|
||||||
right : self.body.body
|
right : self.body.body
|
||||||
})
|
}).transform(compressor)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
return make_node(AST_SimpleStatement, self, {
|
return make_node(AST_SimpleStatement, self, {
|
||||||
body: make_node(AST_Binary, self, {
|
body: make_node(AST_Binary, self, {
|
||||||
operator : "&&",
|
operator : "&&",
|
||||||
left : self.condition,
|
left : self.condition,
|
||||||
right : self.body.body
|
right : self.body.body
|
||||||
})
|
}).transform(compressor)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_EmptyStatement
|
if (self.body instanceof AST_EmptyStatement
|
||||||
@@ -4503,7 +4574,7 @@ merge(Compressor.prototype, {
|
|||||||
operator : "||",
|
operator : "||",
|
||||||
left : self.condition,
|
left : self.condition,
|
||||||
right : self.alternative.body
|
right : self.alternative.body
|
||||||
})
|
}).transform(compressor)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_Exit
|
if (self.body instanceof AST_Exit
|
||||||
@@ -4919,15 +4990,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "charAt":
|
case "charAt":
|
||||||
if (exp.expression.is_string(compressor)) {
|
if (self.args.length < 2) {
|
||||||
var arg = self.args[0];
|
var node = make_node(AST_Sub, self, {
|
||||||
var index = arg ? arg.evaluate(compressor) : 0;
|
expression: exp.expression,
|
||||||
if (index !== arg) {
|
property: self.args.length ? make_node(AST_Binary, self.args[0], {
|
||||||
return make_node(AST_Sub, exp, {
|
operator: "|",
|
||||||
expression: exp.expression,
|
left: make_node(AST_Number, self, {
|
||||||
property: make_node_from_constant(index | 0, arg || exp)
|
value: 0
|
||||||
}).optimize(compressor);
|
}),
|
||||||
}
|
right: self.args[0]
|
||||||
|
}) : make_node(AST_Number, self, {
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
});
|
||||||
|
node.is_string = return_true;
|
||||||
|
return node.optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "apply":
|
case "apply":
|
||||||
@@ -5451,6 +5528,7 @@ merge(Compressor.prototype, {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
function is_object(node) {
|
function is_object(node) {
|
||||||
return node instanceof AST_Array
|
return node instanceof AST_Array
|
||||||
@@ -5490,6 +5568,13 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("comparisons")) switch (self.operator) {
|
if (compressor.option("comparisons")) switch (self.operator) {
|
||||||
case "===":
|
case "===":
|
||||||
case "!==":
|
case "!==":
|
||||||
|
if (is_undefined(self.left, compressor) && self.right.is_defined(compressor)) {
|
||||||
|
compressor.warn("Expression always defined [{file}:{line},{col}]", self.start);
|
||||||
|
return make_sequence(self, [
|
||||||
|
self.right,
|
||||||
|
make_node(self.operator == "===" ? AST_False : AST_True, self)
|
||||||
|
]).optimize(compressor);
|
||||||
|
}
|
||||||
var is_strict_comparison = true;
|
var is_strict_comparison = true;
|
||||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||||
@@ -5528,6 +5613,8 @@ merge(Compressor.prototype, {
|
|||||||
break;
|
break;
|
||||||
case "&&":
|
case "&&":
|
||||||
case "||":
|
case "||":
|
||||||
|
// void 0 !== x && null !== x => null != x
|
||||||
|
// void 0 === x || null === x => null == x
|
||||||
var lhs = self.left;
|
var lhs = self.left;
|
||||||
if (lhs.operator == self.operator) {
|
if (lhs.operator == self.operator) {
|
||||||
lhs = lhs.right;
|
lhs = lhs.right;
|
||||||
@@ -5556,7 +5643,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
|
||||||
|
case "+":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if (ll && typeof ll == "string") {
|
if (ll && typeof ll == "string") {
|
||||||
@@ -5573,6 +5661,20 @@ merge(Compressor.prototype, {
|
|||||||
make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
]).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "==":
|
||||||
|
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||||
|
return make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: self.right
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "!=":
|
||||||
|
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||||
|
return self.right.optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
||||||
if (!(compressor.parent() instanceof AST_Binary)
|
if (!(compressor.parent() instanceof AST_Binary)
|
||||||
@@ -5592,12 +5694,12 @@ merge(Compressor.prototype, {
|
|||||||
if (self.right instanceof AST_String
|
if (self.right instanceof AST_String
|
||||||
&& self.right.getValue() == ""
|
&& self.right.getValue() == ""
|
||||||
&& self.left.is_string(compressor)) {
|
&& self.left.is_string(compressor)) {
|
||||||
return self.left;
|
return self.left.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_String
|
if (self.left instanceof AST_String
|
||||||
&& self.left.getValue() == ""
|
&& self.left.getValue() == ""
|
||||||
&& self.right.is_string(compressor)) {
|
&& self.right.is_string(compressor)) {
|
||||||
return self.right;
|
return self.right.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_Binary
|
if (self.left instanceof AST_Binary
|
||||||
&& self.left.operator == "+"
|
&& self.left.operator == "+"
|
||||||
@@ -5605,7 +5707,7 @@ merge(Compressor.prototype, {
|
|||||||
&& self.left.left.getValue() == ""
|
&& self.left.left.getValue() == ""
|
||||||
&& self.right.is_string(compressor)) {
|
&& self.right.is_string(compressor)) {
|
||||||
self.left = self.left.right;
|
self.left = self.left.right;
|
||||||
return self.transform(compressor);
|
return self.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate")) {
|
if (compressor.option("evaluate")) {
|
||||||
@@ -5860,6 +5962,35 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (compressor.option("unsafe")
|
||||||
|
&& self.right instanceof AST_Call
|
||||||
|
&& self.right.expression instanceof AST_Dot
|
||||||
|
&& indexFns[self.right.expression.property]) {
|
||||||
|
if (compressor.option("booleans")
|
||||||
|
&& (self.operator == "==" || self.operator == "!=")
|
||||||
|
&& self.left instanceof AST_Number
|
||||||
|
&& self.left.getValue() == 0
|
||||||
|
&& compressor.in_boolean_context()) {
|
||||||
|
return (self.operator == "==" ? make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: self.right
|
||||||
|
}) : self.right).optimize(compressor);
|
||||||
|
}
|
||||||
|
if (compressor.option("comparisons") && is_indexOf_match_pattern()) {
|
||||||
|
var node = make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "~",
|
||||||
|
expression: self.right
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (self.operator == "!=" || self.operator == "<=") node = make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: node
|
||||||
|
});
|
||||||
|
return node.optimize(compressor);
|
||||||
|
}
|
||||||
|
}
|
||||||
// x && (y && z) ==> x && y && z
|
// x && (y && z) ==> x && y && z
|
||||||
// x || (y || z) ==> x || y || z
|
// x || (y || z) ==> x || y || z
|
||||||
// x + ("y" + z) ==> x + "y" + z
|
// x + ("y" + z) ==> x + "y" + z
|
||||||
@@ -5893,6 +6024,23 @@ merge(Compressor.prototype, {
|
|||||||
if (node.is_truthy()) return true;
|
if (node.is_truthy()) return true;
|
||||||
return node.evaluate(compressor);
|
return node.evaluate(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_indexOf_match_pattern() {
|
||||||
|
switch (self.operator) {
|
||||||
|
case ">":
|
||||||
|
case "<=":
|
||||||
|
// 0 > array.indexOf(string) => !~array.indexOf(string)
|
||||||
|
// 0 <= array.indexOf(string) => !!~array.indexOf(string)
|
||||||
|
return self.left instanceof AST_Number && self.left.getValue() == 0;
|
||||||
|
case "==":
|
||||||
|
case "!=":
|
||||||
|
// -1 == array.indexOf(string) => !~array.indexOf(string)
|
||||||
|
// -1 != array.indexOf(string) => !!~array.indexOf(string)
|
||||||
|
return self.left instanceof AST_Number && self.left.getValue() == -1
|
||||||
|
|| self.left instanceof AST_UnaryPrefix && self.left.operator == "-"
|
||||||
|
&& self.left.expression instanceof AST_Number && self.left.expression.getValue() == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function recursive_ref(compressor, def) {
|
function recursive_ref(compressor, def) {
|
||||||
@@ -6139,7 +6287,7 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_Exit) {
|
if (parent instanceof AST_Exit) {
|
||||||
if (in_try(level, parent)) break;
|
if (in_try(level, parent)) break;
|
||||||
if (is_reachable(def.scope, [ def ])) break;
|
if (is_reachable(def.scope, [ def ])) break;
|
||||||
if (self.operator == "=") return self.right;
|
if (self.operator == "=") return self.right.optimize(compressor);
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
|
|||||||
@@ -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.5.7",
|
"version": "3.5.9",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -345,3 +345,38 @@ is_boolean_var: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_defined: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function a() {
|
||||||
|
return void 0 === a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function a() {
|
||||||
|
return a, false;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Expression always defined [test/compress/comparisons.js:2,19]",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_indexOf: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
comparisons: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (Object.keys({ foo: 42 }).indexOf("foo") >= 0) console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
if (~Object.keys({ foo: 42 }).indexOf("foo")) console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1416,3 +1416,58 @@ issue_3271: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1 1"
|
expect_stdout: "1 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iife_condition: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (function() {
|
||||||
|
return console;
|
||||||
|
}())
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
return console;
|
||||||
|
}() || console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
angularjs_chain: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function nonComputedMember(left, right, context, create) {
|
||||||
|
var lhs = left();
|
||||||
|
if (create && create !== 1) {
|
||||||
|
if (lhs && lhs[right] == null) {
|
||||||
|
lhs[right] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var value = lhs != null ? lhs[right] : undefined;
|
||||||
|
if (context) {
|
||||||
|
return { context: lhs, name: right, value: value };
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function nonComputedMember(left, right, context, create) {
|
||||||
|
var lhs = left();
|
||||||
|
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
|
||||||
|
var value = null != lhs ? lhs[right] : void 0;
|
||||||
|
return context ? {
|
||||||
|
context: lhs,
|
||||||
|
name: right,
|
||||||
|
value: value
|
||||||
|
} : value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -942,3 +942,21 @@ issue_2929: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_string_replace: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"foo".replace("f", function() {
|
||||||
|
console.log("PASS");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"foo".replace("f", function() {
|
||||||
|
console.log("PASS");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -820,8 +820,8 @@ unsafe_charAt_noop: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
s.charAt(0),
|
s[0],
|
||||||
"string".charAt(x),
|
"string"[0 | x],
|
||||||
(typeof x)[0]
|
(typeof x)[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1712,3 +1712,21 @@ unsafe_escaped: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_string_replace: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"foo".replace("f", function() {
|
||||||
|
console.log("PASS");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"foo".replace("f", function() {
|
||||||
|
console.log("PASS");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
issue_1639_1: {
|
issue_1639_1: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
@@ -12,7 +11,6 @@ issue_1639_1: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = 100, b = 10;
|
var a = 100, b = 10;
|
||||||
|
|
||||||
var L1 = 5;
|
var L1 = 5;
|
||||||
while (--L1 > 0) {
|
while (--L1 > 0) {
|
||||||
if ((--b), false) {
|
if ((--b), false) {
|
||||||
@@ -21,7 +19,6 @@ issue_1639_1: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -29,7 +26,7 @@ issue_1639_1: {
|
|||||||
if (--b, 0) var ignore = 0;
|
if (--b, 0) var ignore = 0;
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: "100 6"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1639_2: {
|
issue_1639_2: {
|
||||||
@@ -44,25 +41,23 @@ issue_1639_2: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = 100, b = 10;
|
var a = 100, b = 10;
|
||||||
|
|
||||||
function f19() {
|
function f19() {
|
||||||
if (++a, false)
|
if (++a, false)
|
||||||
if (a)
|
if (a)
|
||||||
if (++a);
|
if (++a);
|
||||||
}
|
}
|
||||||
f19();
|
f19();
|
||||||
|
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = 100, b = 10;
|
var a = 100, b = 10;
|
||||||
function f19() {
|
function f19() {
|
||||||
++a, 0;
|
++a, 1;
|
||||||
}
|
}
|
||||||
f19(),
|
f19(),
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: "101 10"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1639_3: {
|
issue_1639_3: {
|
||||||
@@ -84,5 +79,5 @@ issue_1639_3: {
|
|||||||
a++,
|
a++,
|
||||||
console.log(a, b);
|
console.log(a, b);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: "101 10"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -702,7 +702,7 @@ side_effects_cascade_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
!(b += a) && ((b = a) || (b -= a, b ^= a)),
|
(b += a) || (b = a) || (b -= a, b ^= a),
|
||||||
a--;
|
a--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -964,3 +964,39 @@ missing_link: {
|
|||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
angularjs_chain: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function nonComputedMember(left, right, context, create) {
|
||||||
|
var lhs = left();
|
||||||
|
if (create && create !== 1) {
|
||||||
|
if (lhs && lhs[right] == null) {
|
||||||
|
lhs[right] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var value = lhs != null ? lhs[right] : undefined;
|
||||||
|
if (context) {
|
||||||
|
return { context: lhs, name: right, value: value };
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function nonComputedMember(left, right, context, create) {
|
||||||
|
var lhs = left();
|
||||||
|
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
|
||||||
|
var value = null != lhs ? lhs[right] : void 0;
|
||||||
|
return context ? {
|
||||||
|
context: lhs,
|
||||||
|
name: right,
|
||||||
|
value: value
|
||||||
|
} : value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user