Compare commits

...

10 Commits

Author SHA1 Message Date
Alex Lam S.L
40ceddb48a v2.8.4 2017-03-02 00:24:49 +08:00
Alex Lam S.L
7aa69117e1 fix corner cases in reduce_vars (#1524)
Avoid variable substitution in the following cases:
- use of variable before declaration
- declaration within conditional code blocks
- declaration within loop body

fixes #1518
fixes #1525
2017-03-02 00:20:53 +08:00
Alex Lam S.L
bff7ad67bb v2.8.3 2017-03-01 15:28:46 +08:00
Alex Lam S.L
c2334baa48 fix crash on missing props to string_template() (#1523)
Patched up `make_node()` without `orig`.

There may be other cases where `start` could be missing, so make it print "undefined" instead of crashing.

fixes #1518
2017-03-01 15:25:26 +08:00
Alex Lam S.L
fb2b6c7c6f v2.8.2 2017-03-01 04:46:12 +08:00
Alex Lam S.L
f5cbe19b75 invert reduce_vars tracking flag (#1519)
Modules like webpack and grunt-contrib-uglify still uses `ast.transform(compressor)` before `Compressor.compress(ast)` was introduced.

Workaround this compatibility issue by deactivating `reduce_vars` in such case.

Also fix use case with omitted `options` when calling `Compressor()`.

fixes #1516
2017-03-01 04:12:10 +08:00
Alex Lam S.L
b34fa11a13 fix evaluate on object getter & setter (#1515) 2017-03-01 02:03:47 +08:00
Alex Lam S.L
320984c5f5 v2.8.1 2017-03-01 00:27:08 +08:00
Alex Lam S.L
4365a51237 temporarily disables reduce_vars (#1517)
... as we investigate #1516
2017-03-01 00:25:43 +08:00
Alex Lam S.L
858e6c78a4 warn & drop #__PURE__ iff IIFE is dropped (#1511)
- consolidate `side-effects` optimisations
- improve string `+` optimisation
- enhance literal & `conditionals` optimisations
2017-02-28 02:25:44 +08:00
12 changed files with 475 additions and 132 deletions

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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];
});
};

View File

@@ -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"
},

View File

@@ -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) {

View File

@@ -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"))) {

View File

@@ -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)
);
}
}

View File

@@ -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]",
]
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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)}");
});
})
});