Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40ceddb48a | ||
|
|
7aa69117e1 | ||
|
|
bff7ad67bb | ||
|
|
c2334baa48 | ||
|
|
fb2b6c7c6f | ||
|
|
f5cbe19b75 | ||
|
|
b34fa11a13 | ||
|
|
320984c5f5 | ||
|
|
4365a51237 | ||
|
|
858e6c78a4 |
@@ -621,7 +621,7 @@ function uglify(ast, options, mangle) {
|
||||
|
||||
// Compression
|
||||
uAST.figure_out_scope();
|
||||
uAST = uAST.transform(UglifyJS.Compressor(options));
|
||||
uAST = UglifyJS.Compressor(options).compress(uAST);
|
||||
|
||||
// Mangling (optional)
|
||||
if (mangle) {
|
||||
@@ -865,7 +865,7 @@ toplevel.figure_out_scope()
|
||||
Like this:
|
||||
```javascript
|
||||
var compressor = UglifyJS.Compressor(options);
|
||||
var compressed_ast = toplevel.transform(compressor);
|
||||
var compressed_ast = compressor.compress(toplevel);
|
||||
```
|
||||
|
||||
The `options` can be missing. Available options are discussed above in
|
||||
|
||||
284
lib/compress.js
284
lib/compress.js
@@ -61,7 +61,7 @@ function Compressor(options, false_by_default) {
|
||||
booleans : !false_by_default,
|
||||
loops : !false_by_default,
|
||||
unused : !false_by_default,
|
||||
toplevel : !!options["top_retain"],
|
||||
toplevel : !!(options && options["top_retain"]),
|
||||
top_retain : null,
|
||||
hoist_funs : !false_by_default,
|
||||
keep_fargs : true,
|
||||
@@ -179,38 +179,105 @@ merge(Compressor.prototype, {
|
||||
|
||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){
|
||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||
var unsafe = compressor.option("unsafe");
|
||||
var safe_ids = [];
|
||||
push();
|
||||
var tw = new TreeWalker(function(node){
|
||||
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
}
|
||||
if (reduce_vars) {
|
||||
if (node instanceof AST_Toplevel) node.globals.each(reset_def);
|
||||
if (node instanceof AST_Scope) node.variables.each(reset_def);
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var d = node.definition();
|
||||
d.references.push(node);
|
||||
if (!d.modified && (d.orig.length > 1 || isModified(node, 0))) {
|
||||
d.modified = true;
|
||||
if (!d.fixed || isModified(node, 0) || !is_safe(d)) {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_Call && node.expression instanceof AST_Function) {
|
||||
node.expression.argnames.forEach(function(arg, i) {
|
||||
arg.definition().init = node.args[i] || make_node(AST_Undefined, node);
|
||||
if (node instanceof AST_VarDef) {
|
||||
var d = node.name.definition();
|
||||
if (d.fixed === undefined) {
|
||||
d.fixed = node.value || make_node(AST_Undefined, node);
|
||||
mark_as_safe(d);
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
var iife;
|
||||
if (node instanceof AST_Function
|
||||
&& (iife = tw.parent()) instanceof AST_Call
|
||||
&& iife.expression === node) {
|
||||
node.argnames.forEach(function(arg, i) {
|
||||
var d = arg.definition();
|
||||
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
|
||||
mark_as_safe(d);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
if (node instanceof AST_If || node instanceof AST_DWLoop) {
|
||||
node.condition.walk(tw);
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
if (node.alternative) {
|
||||
push();
|
||||
node.alternative.walk(tw);
|
||||
pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LabeledStatement) {
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_For) {
|
||||
if (node.init) node.init.walk(tw);
|
||||
push();
|
||||
if (node.condition) node.condition.walk(tw);
|
||||
node.body.walk(tw);
|
||||
if (node.step) node.step.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_ForIn) {
|
||||
if (node.init instanceof AST_SymbolRef) {
|
||||
node.init.definition().fixed = false;
|
||||
}
|
||||
node.object.walk(tw);
|
||||
push();
|
||||
node.body.walk(tw);
|
||||
pop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.walk(tw);
|
||||
|
||||
function mark_as_safe(def) {
|
||||
safe_ids[safe_ids.length - 1][def.id] = true;
|
||||
}
|
||||
|
||||
function is_safe(def) {
|
||||
for (var i = safe_ids.length, id = def.id; --i >= 0;) {
|
||||
if (safe_ids[i][id]) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function push() {
|
||||
safe_ids.push(Object.create(null));
|
||||
}
|
||||
|
||||
function pop() {
|
||||
safe_ids.pop();
|
||||
}
|
||||
|
||||
function reset_def(def) {
|
||||
def.modified = false;
|
||||
def.fixed = undefined;
|
||||
def.references = [];
|
||||
def.should_replace = undefined;
|
||||
if (unsafe && def.init) {
|
||||
def.init._evaluated = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function isModified(node, level) {
|
||||
@@ -1148,11 +1215,14 @@ merge(Compressor.prototype, {
|
||||
def(AST_Statement, function(){
|
||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||
});
|
||||
// XXX: AST_Accessor and AST_Function both inherit from AST_Scope,
|
||||
// which itself inherits from AST_Statement; however, they aren't
|
||||
// really statements. This could bite in other places too. :-(
|
||||
// Wish JS had multiple inheritance.
|
||||
def(AST_Accessor, function(){
|
||||
throw def;
|
||||
});
|
||||
def(AST_Function, function(){
|
||||
// XXX: AST_Function inherits from AST_Scope, which itself
|
||||
// inherits from AST_Statement; however, an AST_Function
|
||||
// isn't really a statement. This could byte in other
|
||||
// places too. :-( Wish JS had multiple inheritance.
|
||||
throw def;
|
||||
});
|
||||
function ev(node, compressor) {
|
||||
@@ -1180,7 +1250,9 @@ merge(Compressor.prototype, {
|
||||
for (var i = 0, len = this.properties.length; i < len; i++) {
|
||||
var prop = this.properties[i];
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Node) {
|
||||
if (key instanceof AST_Symbol) {
|
||||
key = key.name;
|
||||
} else if (key instanceof AST_Node) {
|
||||
key = ev(key, compressor);
|
||||
}
|
||||
if (typeof Object.prototype[key] === 'function') {
|
||||
@@ -1258,14 +1330,14 @@ merge(Compressor.prototype, {
|
||||
this._evaluating = true;
|
||||
try {
|
||||
var d = this.definition();
|
||||
if (compressor.option("reduce_vars") && !d.modified && d.init) {
|
||||
if (compressor.option("reduce_vars") && d.fixed) {
|
||||
if (compressor.option("unsafe")) {
|
||||
if (d.init._evaluated === undefined) {
|
||||
d.init._evaluated = ev(d.init, compressor);
|
||||
if (!HOP(d.fixed, "_evaluated")) {
|
||||
d.fixed._evaluated = ev(d.fixed, compressor);
|
||||
}
|
||||
return d.init._evaluated;
|
||||
return d.fixed._evaluated;
|
||||
}
|
||||
return ev(d.init, compressor);
|
||||
return ev(d.fixed, compressor);
|
||||
}
|
||||
} finally {
|
||||
this._evaluating = false;
|
||||
@@ -1375,9 +1447,7 @@ merge(Compressor.prototype, {
|
||||
&& (comments = this.start.comments_before)
|
||||
&& comments.length
|
||||
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
|
||||
compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
|
||||
last_comment.value = last_comment.value.replace(/[@#]__PURE__/g, ' ');
|
||||
pure = true;
|
||||
pure = last_comment;
|
||||
}
|
||||
return this.pure = pure;
|
||||
});
|
||||
@@ -1676,8 +1746,7 @@ merge(Compressor.prototype, {
|
||||
line : def.name.start.line,
|
||||
col : def.name.start.col
|
||||
};
|
||||
if (def.value && def.value.has_side_effects(compressor)) {
|
||||
def._unused_side_effects = true;
|
||||
if (def.value && (def._unused_side_effects = def.value.drop_side_effect_free(compressor))) {
|
||||
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
|
||||
return true;
|
||||
}
|
||||
@@ -1697,7 +1766,7 @@ merge(Compressor.prototype, {
|
||||
for (var i = 0; i < def.length;) {
|
||||
var x = def[i];
|
||||
if (x._unused_side_effects) {
|
||||
side_effects.push(x.value);
|
||||
side_effects.push(x._unused_side_effects);
|
||||
def.splice(i, 1);
|
||||
} else {
|
||||
if (side_effects.length > 0) {
|
||||
@@ -1927,6 +1996,10 @@ merge(Compressor.prototype, {
|
||||
def(AST_This, return_null);
|
||||
def(AST_Call, function(compressor, first_in_statement){
|
||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return this;
|
||||
if (this.pure) {
|
||||
compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
|
||||
this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' ');
|
||||
}
|
||||
var args = trim(this.args, compressor, first_in_statement);
|
||||
return args && AST_Seq.from_array(args);
|
||||
});
|
||||
@@ -1978,8 +2051,17 @@ merge(Compressor.prototype, {
|
||||
case "typeof":
|
||||
if (this.expression instanceof AST_SymbolRef) return null;
|
||||
default:
|
||||
if (first_in_statement && is_iife_call(this.expression)) return this;
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement
|
||||
&& this instanceof AST_UnaryPrefix
|
||||
&& is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator.length === 1) return this;
|
||||
return make_node(AST_UnaryPrefix, this, {
|
||||
operator: this.operator.length === 1 ? this.operator : "!",
|
||||
expression: expression
|
||||
});
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
});
|
||||
def(AST_SymbolRef, function() {
|
||||
@@ -2027,10 +2109,6 @@ merge(Compressor.prototype, {
|
||||
OPT(AST_SimpleStatement, function(self, compressor){
|
||||
if (compressor.option("side_effects")) {
|
||||
var body = self.body;
|
||||
if (!body.has_side_effects(compressor)) {
|
||||
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
}
|
||||
var node = body.drop_side_effect_free(compressor, true);
|
||||
if (!node) {
|
||||
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
||||
@@ -2183,7 +2261,7 @@ merge(Compressor.prototype, {
|
||||
// here because they are only used in an equality comparison later on.
|
||||
self.condition = negated;
|
||||
var tmp = self.body;
|
||||
self.body = self.alternative || make_node(AST_EmptyStatement);
|
||||
self.body = self.alternative || make_node(AST_EmptyStatement, self);
|
||||
self.alternative = tmp;
|
||||
}
|
||||
if (is_empty(self.body) && is_empty(self.alternative)) {
|
||||
@@ -2448,7 +2526,7 @@ merge(Compressor.prototype, {
|
||||
case "Boolean":
|
||||
if (self.args.length == 0) return make_node(AST_False, self);
|
||||
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
|
||||
expression: make_node(AST_UnaryPrefix, null, {
|
||||
expression: make_node(AST_UnaryPrefix, self, {
|
||||
expression: self.args[0],
|
||||
operator: "!"
|
||||
}),
|
||||
@@ -2647,17 +2725,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (!self.car.has_side_effects(compressor)
|
||||
&& !self.cdr.has_side_effects(compressor)
|
||||
&& self.car.equivalent_to(self.cdr)) {
|
||||
return self.car;
|
||||
}
|
||||
}
|
||||
if (self.cdr instanceof AST_UnaryPrefix
|
||||
&& self.cdr.operator == "void"
|
||||
&& !self.cdr.expression.has_side_effects(compressor)) {
|
||||
self.cdr.expression = self.car;
|
||||
return self.cdr;
|
||||
}
|
||||
if (self.cdr instanceof AST_Undefined) {
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator : "void",
|
||||
@@ -2686,8 +2757,20 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_UnaryPrefix, function(self, compressor){
|
||||
self = self.lift_sequences(compressor);
|
||||
var seq = self.lift_sequences(compressor);
|
||||
if (seq !== self) {
|
||||
return seq;
|
||||
}
|
||||
var e = self.expression;
|
||||
if (compressor.option("side_effects") && self.operator == "void") {
|
||||
e = e.drop_side_effect_free(compressor);
|
||||
if (e) {
|
||||
self.expression = e;
|
||||
return self;
|
||||
} else {
|
||||
return make_node(AST_Undefined, self);
|
||||
}
|
||||
}
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
switch (self.operator) {
|
||||
case "!":
|
||||
@@ -2704,13 +2787,10 @@ merge(Compressor.prototype, {
|
||||
// typeof always returns a non-empty string, thus it's
|
||||
// always true in booleans
|
||||
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
||||
if (self.expression.has_side_effects(compressor)) {
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.expression,
|
||||
cdr: make_node(AST_True, self)
|
||||
});
|
||||
}
|
||||
return make_node(AST_True, self);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: e,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
return self.evaluate(compressor)[0];
|
||||
@@ -2840,13 +2920,10 @@ merge(Compressor.prototype, {
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
|
||||
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||
if (self.left.has_side_effects(compressor)) {
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_False)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
return make_node(AST_False, self);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_False, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (ll.length > 1 && ll[1]) {
|
||||
return rr[0];
|
||||
@@ -2860,13 +2937,10 @@ merge(Compressor.prototype, {
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
|
||||
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||
if (self.left.has_side_effects(compressor)) {
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_True)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
return make_node(AST_True, self);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (ll.length > 1 && !ll[1]) {
|
||||
return rr[0];
|
||||
@@ -2878,10 +2952,19 @@ merge(Compressor.prototype, {
|
||||
case "+":
|
||||
var ll = self.left.evaluate(compressor);
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1] && !self.right.has_side_effects(compressor)) ||
|
||||
(rr.length > 1 && rr[0] instanceof AST_String && rr[1] && !self.left.has_side_effects(compressor))) {
|
||||
if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
|
||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_True, self);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.right,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
|
||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.left,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3030,9 +3113,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
||||
var d = self.definition();
|
||||
if (!d.modified && d.init) {
|
||||
if (d.fixed) {
|
||||
if (d.should_replace === undefined) {
|
||||
var init = d.init.evaluate(compressor);
|
||||
var init = d.fixed.evaluate(compressor);
|
||||
if (init.length > 1) {
|
||||
var value = init[0].print_to_string().length;
|
||||
var name = d.name.length;
|
||||
@@ -3131,7 +3214,8 @@ merge(Compressor.prototype, {
|
||||
&& alternative instanceof AST_Assign
|
||||
&& consequent.operator == alternative.operator
|
||||
&& consequent.left.equivalent_to(alternative.left)
|
||||
&& !consequent.left.has_side_effects(compressor)
|
||||
&& (!consequent.left.has_side_effects(compressor)
|
||||
|| !self.condition.has_side_effects(compressor))
|
||||
) {
|
||||
/*
|
||||
* Stuff like this:
|
||||
@@ -3149,25 +3233,19 @@ merge(Compressor.prototype, {
|
||||
})
|
||||
});
|
||||
}
|
||||
// x ? y(a) : y(b) --> y(x ? a : b)
|
||||
if (consequent instanceof AST_Call
|
||||
&& alternative.TYPE === consequent.TYPE
|
||||
&& consequent.args.length == alternative.args.length
|
||||
&& !consequent.expression.has_side_effects(compressor)
|
||||
&& consequent.expression.equivalent_to(alternative.expression)) {
|
||||
if (consequent.args.length == 0) {
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.condition,
|
||||
cdr: consequent
|
||||
});
|
||||
}
|
||||
if (consequent.args.length == 1) {
|
||||
consequent.args[0] = make_node(AST_Conditional, self, {
|
||||
condition: self.condition,
|
||||
consequent: consequent.args[0],
|
||||
alternative: alternative.args[0]
|
||||
});
|
||||
return consequent;
|
||||
}
|
||||
&& consequent.args.length == 1
|
||||
&& alternative.args.length == 1
|
||||
&& consequent.expression.equivalent_to(alternative.expression)
|
||||
&& !consequent.expression.has_side_effects(compressor)) {
|
||||
consequent.args[0] = make_node(AST_Conditional, self, {
|
||||
condition: self.condition,
|
||||
consequent: consequent.args[0],
|
||||
alternative: alternative.args[0]
|
||||
});
|
||||
return consequent;
|
||||
}
|
||||
// x?y?z:a:a --> x&&y?z:a
|
||||
if (consequent instanceof AST_Conditional
|
||||
@@ -3182,16 +3260,12 @@ merge(Compressor.prototype, {
|
||||
alternative: alternative
|
||||
});
|
||||
}
|
||||
// y?1:1 --> 1
|
||||
if (consequent.is_constant()
|
||||
&& alternative.is_constant()
|
||||
&& consequent.equivalent_to(alternative)) {
|
||||
var consequent_value = consequent.evaluate(compressor)[0];
|
||||
if (self.condition.has_side_effects(compressor)) {
|
||||
return AST_Seq.from_array([self.condition, consequent_value]);
|
||||
} else {
|
||||
return consequent_value;
|
||||
}
|
||||
// x ? y : y --> x, y
|
||||
if (consequent.equivalent_to(alternative)) {
|
||||
return make_node(AST_Seq, self, {
|
||||
car: self.condition,
|
||||
cdr: consequent
|
||||
}).optimize(compressor);
|
||||
}
|
||||
|
||||
if (is_true(self.consequent)) {
|
||||
@@ -3350,8 +3424,12 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
function literals_in_boolean_context(self, compressor) {
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {
|
||||
return make_node(AST_True, self);
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
var best = first_in_statement(compressor) ? best_of_statement : best_of;
|
||||
return best(self, make_node(AST_Seq, self, {
|
||||
car: self,
|
||||
cdr: make_node(AST_True, self)
|
||||
}).optimize(compressor));
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
@@ -185,7 +185,7 @@ function push_uniq(array, el) {
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/\{(.+?)\}/g, function(str, p){
|
||||
return props[p];
|
||||
return props && props[p];
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "http://lisperator.net/uglifyjs",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "2.8.0",
|
||||
"version": "2.8.4",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -50,7 +50,8 @@ ifs_3_should_warn: {
|
||||
conditionals : true,
|
||||
dead_code : true,
|
||||
evaluate : true,
|
||||
booleans : true
|
||||
booleans : true,
|
||||
side_effects : true,
|
||||
};
|
||||
input: {
|
||||
var x, y;
|
||||
@@ -135,16 +136,28 @@ ifs_6: {
|
||||
comparisons: true
|
||||
};
|
||||
input: {
|
||||
var x;
|
||||
var x, y;
|
||||
if (!foo && !bar && !baz && !boo) {
|
||||
x = 10;
|
||||
} else {
|
||||
x = 20;
|
||||
}
|
||||
if (y) {
|
||||
x[foo] = 10;
|
||||
} else {
|
||||
x[foo] = 20;
|
||||
}
|
||||
if (foo) {
|
||||
x[bar] = 10;
|
||||
} else {
|
||||
x[bar] = 20;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var x;
|
||||
var x, y;
|
||||
x = foo || bar || baz || boo ? 20 : 10;
|
||||
x[foo] = y ? 10 : 20;
|
||||
foo ? x[bar] = 10 : x[bar] = 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,10 +172,16 @@ cond_1: {
|
||||
} else {
|
||||
do_something(y);
|
||||
}
|
||||
if (some_condition()) {
|
||||
side_effects(x);
|
||||
} else {
|
||||
side_effects(y);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var do_something;
|
||||
do_something(some_condition() ? x : y);
|
||||
some_condition() ? side_effects(x) : side_effects(y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,10 +232,16 @@ cond_4: {
|
||||
} else {
|
||||
do_something();
|
||||
}
|
||||
if (some_condition()) {
|
||||
side_effects();
|
||||
} else {
|
||||
side_effects();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var do_something;
|
||||
some_condition(), do_something();
|
||||
some_condition(), side_effects();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +275,8 @@ cond_5: {
|
||||
cond_7: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate : true
|
||||
evaluate : true,
|
||||
side_effects: true,
|
||||
};
|
||||
input: {
|
||||
var x, y, z, a, b;
|
||||
@@ -714,6 +740,7 @@ issue_1154: {
|
||||
conditionals: true,
|
||||
evaluate : true,
|
||||
booleans : true,
|
||||
side_effects: true,
|
||||
};
|
||||
input: {
|
||||
function f1(x) { return x ? -1 : -1; }
|
||||
@@ -742,7 +769,7 @@ issue_1154: {
|
||||
function g2() { return g(), 2; }
|
||||
function g3() { return g(), -4; }
|
||||
function g4() { return g(), !1; }
|
||||
function g5() { return g(), void 0; }
|
||||
function g5() { return void g(); }
|
||||
function g6() { return g(), "number"; }
|
||||
}
|
||||
}
|
||||
@@ -750,7 +777,8 @@ issue_1154: {
|
||||
no_evaluate: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate : false
|
||||
evaluate : false,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function f(b) {
|
||||
|
||||
@@ -64,7 +64,8 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
loops : true,
|
||||
booleans : true,
|
||||
conditionals : true,
|
||||
evaluate : true
|
||||
evaluate : true,
|
||||
side_effects : true,
|
||||
};
|
||||
input: {
|
||||
while (!((foo && bar) || (x + "0"))) {
|
||||
|
||||
@@ -337,6 +337,32 @@ unsafe_object_repeated: {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe_object_accessor: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var a = {
|
||||
get b() {},
|
||||
set b() {}
|
||||
};
|
||||
return {a:a};
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
var a = {
|
||||
get b() {},
|
||||
set b() {}
|
||||
};
|
||||
return {a:a};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe_function: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
@@ -624,25 +650,35 @@ in_boolean_context: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
!42;
|
||||
!"foo";
|
||||
![1, 2];
|
||||
!/foo/;
|
||||
!b(42);
|
||||
!b("foo");
|
||||
!b([1, 2]);
|
||||
!b(/foo/);
|
||||
console.log(
|
||||
!42,
|
||||
!"foo",
|
||||
![1, 2],
|
||||
!/foo/,
|
||||
!b(42),
|
||||
!b("foo"),
|
||||
!b([1, 2]),
|
||||
!b(/foo/),
|
||||
![1, foo()],
|
||||
![1, foo(), 2]
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
!1;
|
||||
!1;
|
||||
!1;
|
||||
!1;
|
||||
!b(42);
|
||||
!b("foo");
|
||||
!b([1, 2]);
|
||||
!b(/foo/);
|
||||
console.log(
|
||||
!1,
|
||||
!1,
|
||||
!1,
|
||||
!1,
|
||||
!b(42),
|
||||
!b("foo"),
|
||||
!b([1, 2]),
|
||||
!b(/foo/),
|
||||
![1, foo()],
|
||||
(foo(), !1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,3 +116,61 @@ pure_function_calls_toplevel: {
|
||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
||||
]
|
||||
}
|
||||
|
||||
should_warn: {
|
||||
options = {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
/* @__PURE__ */(function(){x})(), void/* @__PURE__ */(function(){y})();
|
||||
/* @__PURE__ */(function(){x})() || true ? foo() : bar();
|
||||
true || /* @__PURE__ */(function(){y})() ? foo() : bar();
|
||||
/* @__PURE__ */(function(){x})() && false ? foo() : bar();
|
||||
false && /* @__PURE__ */(function(){y})() ? foo() : bar();
|
||||
/* @__PURE__ */(function(){x})() + "foo" ? bar() : baz();
|
||||
"foo" + /* @__PURE__ */(function(){y})() ? bar() : baz();
|
||||
/* @__PURE__ */(function(){x})() ? foo() : foo();
|
||||
[/* @__PURE__ */(function(){x})()] ? foo() : bar();
|
||||
!{ foo: /* @__PURE__ */(function(){x})() } ? bar() : baz();
|
||||
}
|
||||
expect: {
|
||||
foo();
|
||||
foo();
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
foo();
|
||||
foo();
|
||||
baz();
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:130,8]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:132,8]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:136,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:137,8]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ string_plus_optimization: {
|
||||
throw "nope";
|
||||
}
|
||||
try {
|
||||
console.log('0' + throwing_function() ? "yes" : "no");
|
||||
console.log((throwing_function(), "yes"));
|
||||
} catch (ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
|
||||
@@ -470,3 +470,122 @@ multi_def_2: {
|
||||
var repeatLength = this.getBits(bitsLength) + bitsOffset;
|
||||
}
|
||||
}
|
||||
|
||||
use_before_var: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(t);
|
||||
var t = 1;
|
||||
}
|
||||
expect: {
|
||||
console.log(t);
|
||||
var t = 1;
|
||||
}
|
||||
}
|
||||
|
||||
inner_var_if: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(){
|
||||
return 0;
|
||||
}
|
||||
if (f())
|
||||
var t = 1;
|
||||
if (!t)
|
||||
console.log(t);
|
||||
}
|
||||
expect: {
|
||||
function f(){
|
||||
return 0;
|
||||
}
|
||||
if (f())
|
||||
var t = 1;
|
||||
if (!t)
|
||||
console.log(t);
|
||||
}
|
||||
}
|
||||
|
||||
inner_var_label: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(){
|
||||
return 1;
|
||||
}
|
||||
l: {
|
||||
if (f()) break l;
|
||||
var t = 1;
|
||||
}
|
||||
console.log(t);
|
||||
}
|
||||
expect: {
|
||||
function f(){
|
||||
return 1;
|
||||
}
|
||||
l: {
|
||||
if (f()) break l;
|
||||
var t = 1;
|
||||
}
|
||||
console.log(t);
|
||||
}
|
||||
}
|
||||
|
||||
inner_var_for: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
x(a, b, d);
|
||||
for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) {
|
||||
var d = 4, e = 5;
|
||||
x(a, b, c, d, e);
|
||||
}
|
||||
x(a, b, c, d, e)
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
x(1, b, d);
|
||||
for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) {
|
||||
var d = 4, e = 5;
|
||||
x(1, b, 3, d, e);
|
||||
}
|
||||
x(1, b, 3, d, e);
|
||||
}
|
||||
}
|
||||
|
||||
inner_var_for_in: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = 2;
|
||||
for (b in (function() {
|
||||
return x(a, b, c);
|
||||
})()) {
|
||||
var c = 3, d = 4;
|
||||
x(a, b, c, d);
|
||||
}
|
||||
x(a, b, c, d);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = 2;
|
||||
for (b in (function() {
|
||||
return x(1, b, c);
|
||||
})()) {
|
||||
var c = 3, d = 4;
|
||||
x(1, b, c, d);
|
||||
}
|
||||
x(1, b, c, d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ typeof_in_boolean_context: {
|
||||
booleans : true,
|
||||
evaluate : true,
|
||||
conditionals : true,
|
||||
side_effects : true,
|
||||
};
|
||||
input: {
|
||||
function f1(x) { return typeof x ? "yes" : "no"; }
|
||||
@@ -36,12 +37,14 @@ typeof_in_boolean_context: {
|
||||
typeof 0 ? foo() : bar();
|
||||
!typeof console.log(1);
|
||||
var a = !typeof console.log(2);
|
||||
if (typeof (1 + foo()));
|
||||
}
|
||||
expect: {
|
||||
function f1(x) { return "yes"; }
|
||||
function f2() { return g(), "Yes"; }
|
||||
foo();
|
||||
!(console.log(1), !0);
|
||||
console.log(1);
|
||||
var a = !(console.log(2), !0);
|
||||
foo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,17 @@ describe("minify", function() {
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "// comment1 comment2\nbar();");
|
||||
});
|
||||
it("should not drop #__PURE__ hint if function is retained", function() {
|
||||
var result = Uglify.minify("var a = /*#__PURE__*/(function(){return 1})();", {
|
||||
fromString: true,
|
||||
output: {
|
||||
comments: "all",
|
||||
beautify: false,
|
||||
}
|
||||
});
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "var a=/*#__PURE__*/function(){return 1}();");
|
||||
})
|
||||
});
|
||||
|
||||
describe("JS_Parse_Error", function() {
|
||||
@@ -171,4 +182,13 @@ describe("minify", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Compressor", function() {
|
||||
it("should be backward compatible with ast.transform(compressor)", function() {
|
||||
var ast = Uglify.parse("function f(a){for(var i=0;i<a;i++)console.log(i)}");
|
||||
ast.figure_out_scope();
|
||||
ast = ast.transform(Uglify.Compressor());
|
||||
assert.strictEqual(ast.print_to_string(), "function f(a){for(var i=0;i<a;i++)console.log(i)}");
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user