Merge branch 'master' into harmony-v3.3.10
This commit is contained in:
61
CONTRIBUTING.md
Normal file
61
CONTRIBUTING.md
Normal file
@@ -0,0 +1,61 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
## Documentation
|
||||
|
||||
Every new feature and API change should be accompanied by a README additon.
|
||||
|
||||
## Testing
|
||||
|
||||
All features and bugs should have tests that verify the fix. You can run all
|
||||
tests using `npm test`.
|
||||
|
||||
The most common type of test are tests that verify input and output of the
|
||||
Uglify transforms. These tests exist in `test/compress`. New tests can be added
|
||||
either to an existing file or in a new file `issue-xxx.js`.
|
||||
|
||||
Tests that cannot be expressed as a simple AST can be found in `test/mocha`.
|
||||
|
||||
## Code style
|
||||
|
||||
- File encoding must be `UTF-8`.
|
||||
- `LF` is always used as a line ending.
|
||||
- Statements end with semicolons.
|
||||
- Indentation uses 4 spaces, switch `case` 2 spaces.
|
||||
- Identifiers use `snake_case`.
|
||||
- Strings use double quotes (`"`).
|
||||
- Use a trailing comma for multiline array and object literals to minimize diffs.
|
||||
- The Uglify code only uses ES5, even in the `harmony` branch.
|
||||
- Line length should be at most 80 cols, except when it is easier to read a
|
||||
longer line.
|
||||
- If both sides of a comparison are of the same type, `==` and `!=` are used.
|
||||
- Multiline conditions place `&&` and `||` first on the line.
|
||||
|
||||
**Example feature**
|
||||
|
||||
```js
|
||||
OPT(AST_Debugger, function(self, compressor) {
|
||||
if (compressor.option("drop_debugger"))
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
return self;
|
||||
});
|
||||
```
|
||||
|
||||
**Example test case**
|
||||
|
||||
```js
|
||||
drop_debugger: {
|
||||
options = {
|
||||
drop_debugger: true,
|
||||
}
|
||||
input: {
|
||||
debugger;
|
||||
if (foo) debugger;
|
||||
}
|
||||
expect: {
|
||||
if (foo);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
UglifyJS is released under the BSD license:
|
||||
|
||||
Copyright 2012-2013 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
Copyright 2012-2018 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
||||
24
README.md
24
README.md
@@ -1173,3 +1173,27 @@ To enable fast minify mode with the API use:
|
||||
```js
|
||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||
```
|
||||
|
||||
#### Source maps and debugging
|
||||
|
||||
Various `compress` transforms that simplify, rearrange, inline and remove code
|
||||
are known to have an adverse effect on debugging with source maps. This is
|
||||
expected as code is optimized and mappings are often simply not possible as
|
||||
some code no longer exists. For highest fidelity in source map debugging
|
||||
disable the Uglify `compress` option and just use `mangle`.
|
||||
|
||||
### Compiler assumptions
|
||||
|
||||
To allow for better optimizations, the compiler makes various assumptions:
|
||||
|
||||
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
||||
objects they have not been overridden.
|
||||
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
||||
- `arguments.callee`, `arguments.caller` and `Function.prototype.caller` are not used.
|
||||
- The code doesn't expect the contents of `Function.prototype.toString()` or
|
||||
`Error.prototype.stack` to be anything in particular.
|
||||
- Getting and setting properties on a plain object does not cause other side effects
|
||||
(using `.watch()` or `Proxy`).
|
||||
- Object properties can be added, removed and modified (not prevented with
|
||||
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
||||
`Object.preventExtensions()` or `Object.seal()`).
|
||||
|
||||
278
lib/compress.js
278
lib/compress.js
@@ -327,6 +327,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function reset_def(compressor, def) {
|
||||
def.assignments = 0;
|
||||
def.chained = false;
|
||||
def.direct_access = false;
|
||||
def.escaped = false;
|
||||
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||
@@ -512,19 +513,27 @@ merge(Compressor.prototype, {
|
||||
node.left.walk(suppressor);
|
||||
return;
|
||||
}
|
||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||
if (!(node.left instanceof AST_SymbolRef)) return;
|
||||
var d = node.left.definition();
|
||||
if (safe_to_assign(tw, d, node.right)) {
|
||||
d.references.push(node.left);
|
||||
d.assignments++;
|
||||
d.fixed = function() {
|
||||
return node.right;
|
||||
};
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
}
|
||||
var fixed = d.fixed;
|
||||
if (!fixed && node.operator != "=") return;
|
||||
if (!safe_to_assign(tw, d, node.right)) return;
|
||||
d.references.push(node.left);
|
||||
d.assignments++;
|
||||
if (node.operator != "=") d.chained = true;
|
||||
d.fixed = node.operator == "=" ? function() {
|
||||
return node.right;
|
||||
} : function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: fixed instanceof AST_Node ? fixed : fixed(),
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
});
|
||||
def(AST_Binary, function(tw) {
|
||||
if (!lazy_op(this.operator)) return;
|
||||
@@ -722,6 +731,32 @@ merge(Compressor.prototype, {
|
||||
if (this.bfinally) this.bfinally.walk(tw);
|
||||
return true;
|
||||
});
|
||||
def(AST_Unary, function(tw, descend) {
|
||||
var node = this;
|
||||
if (node.operator != "++" && node.operator != "--") return;
|
||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
||||
var d = node.expression.definition();
|
||||
var fixed = d.fixed;
|
||||
if (!fixed) return;
|
||||
if (!safe_to_assign(tw, d, true)) return;
|
||||
d.references.push(node.expression);
|
||||
d.assignments++;
|
||||
d.chained = true;
|
||||
d.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: make_node(AST_UnaryPrefix, node, {
|
||||
operator: "+",
|
||||
expression: fixed instanceof AST_Node ? fixed : fixed()
|
||||
}),
|
||||
right: make_node(AST_Number, node, {
|
||||
value: 1
|
||||
})
|
||||
});
|
||||
};
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
});
|
||||
def(AST_VarDef, function(tw, descend) {
|
||||
var node = this;
|
||||
if (node.name instanceof AST_Destructuring) {
|
||||
@@ -729,19 +764,19 @@ merge(Compressor.prototype, {
|
||||
return;
|
||||
}
|
||||
var d = node.name.definition();
|
||||
if (safe_to_assign(tw, d, node.value)) {
|
||||
if (node.value) {
|
||||
if (node.value) {
|
||||
if (safe_to_assign(tw, d, node.value)) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
tw.loop_ids[d.id] = tw.in_loop;
|
||||
mark(tw, d, false);
|
||||
descend();
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
} else if (node.value) {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
def(AST_While, function(tw, descend, compressor) {
|
||||
@@ -995,32 +1030,11 @@ merge(Compressor.prototype, {
|
||||
var stat_index = statements.length;
|
||||
var scanner = new TreeTransformer(function(node, descend) {
|
||||
if (abort) return node;
|
||||
// Scan case expressions first in a switch statement
|
||||
if (node instanceof AST_Switch) {
|
||||
if (!hit) {
|
||||
if (node !== hit_stack[hit_index]) return node;
|
||||
hit_index++;
|
||||
}
|
||||
node.expression = node.expression.transform(scanner);
|
||||
for (var i = 0, len = node.body.length; !abort && i < len; i++) {
|
||||
var branch = node.body[i];
|
||||
if (branch instanceof AST_Case) {
|
||||
if (!hit) {
|
||||
if (branch !== hit_stack[hit_index]) continue;
|
||||
hit_index++;
|
||||
}
|
||||
branch.expression = branch.expression.transform(scanner);
|
||||
if (side_effects || !replace_all) break;
|
||||
}
|
||||
}
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
// Skip nodes before `candidate` as quickly as possible
|
||||
if (!hit) {
|
||||
if (node !== hit_stack[hit_index]) return node;
|
||||
hit_index++;
|
||||
if (hit_index < hit_stack.length) return;
|
||||
if (hit_index < hit_stack.length) return handle_custom_scan_order(node);
|
||||
hit = true;
|
||||
stop_after = find_stop(node, 0);
|
||||
if (stop_after === node) abort = true;
|
||||
@@ -1034,6 +1048,7 @@ merge(Compressor.prototype, {
|
||||
|| node instanceof AST_Debugger
|
||||
|| node instanceof AST_Destructuring
|
||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||
|| node instanceof AST_LoopControl
|
||||
|| node instanceof AST_Try
|
||||
|| node instanceof AST_With
|
||||
|| parent instanceof AST_For && node !== parent.init
|
||||
@@ -1042,10 +1057,21 @@ merge(Compressor.prototype, {
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
// Stop only if candidate is found within conditional branches
|
||||
if (!stop_if_hit && (side_effects || !replace_all)
|
||||
&& (parent instanceof AST_Binary && lazy_op(parent.operator) && parent.left !== node
|
||||
|| parent instanceof AST_Conditional && parent.condition !== node
|
||||
|| parent instanceof AST_If && parent.condition !== node)) {
|
||||
stop_if_hit = parent;
|
||||
}
|
||||
// Replace variable with assignment when found
|
||||
if (can_replace
|
||||
&& !(node instanceof AST_SymbolDeclaration)
|
||||
&& lhs.equivalent_to(node)) {
|
||||
if (stop_if_hit) {
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
if (is_lhs(node, parent)) {
|
||||
if (value_def) replaced++;
|
||||
return node;
|
||||
@@ -1090,26 +1116,25 @@ merge(Compressor.prototype, {
|
||||
var sym;
|
||||
if (node instanceof AST_Call
|
||||
|| node instanceof AST_Exit
|
||||
&& (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs))
|
||||
|| node instanceof AST_PropAccess
|
||||
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
||||
|| node instanceof AST_SymbolRef
|
||||
&& (lvalues[node.name]
|
||||
|| side_effects && !references_in_scope(node.definition()))
|
||||
|| (sym = lhs_or_def(node))
|
||||
&& (lvalues[node.name] || side_effects && may_modify(node))
|
||||
|| node instanceof AST_VarDef && node.value
|
||||
&& (node.name.name in lvalues || side_effects && may_modify(node.name))
|
||||
|| (sym = is_lhs(node.left, node))
|
||||
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|
||||
|| may_throw
|
||||
&& (in_try ? node.has_side_effects(compressor) : side_effects_external(node))
|
||||
|| (side_effects || !replace_all)
|
||||
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|
||||
|| parent instanceof AST_Conditional
|
||||
|| parent instanceof AST_If)) {
|
||||
&& (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) {
|
||||
stop_after = node;
|
||||
if (node instanceof AST_Scope) abort = true;
|
||||
}
|
||||
// Skip (non-executed) functions
|
||||
if (node instanceof AST_Scope) return node;
|
||||
return handle_custom_scan_order(node);
|
||||
}, function(node) {
|
||||
if (!abort && stop_after === node) abort = true;
|
||||
if (abort) return;
|
||||
if (stop_after === node) abort = true;
|
||||
if (stop_if_hit === node) stop_if_hit = null;
|
||||
});
|
||||
var multi_replacer = new TreeTransformer(function(node) {
|
||||
if (abort) return node;
|
||||
@@ -1148,6 +1173,7 @@ merge(Compressor.prototype, {
|
||||
var candidate = hit_stack[hit_stack.length - 1];
|
||||
var value_def = null;
|
||||
var stop_after = null;
|
||||
var stop_if_hit = null;
|
||||
var lhs = get_lhs(candidate);
|
||||
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
@@ -1191,6 +1217,28 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function handle_custom_scan_order(node) {
|
||||
// Skip (non-executed) functions
|
||||
if (node instanceof AST_Scope) return node;
|
||||
// Scan case expressions first in a switch statement
|
||||
if (node instanceof AST_Switch) {
|
||||
node.expression = node.expression.transform(scanner);
|
||||
for (var i = 0, len = node.body.length; !abort && i < len; i++) {
|
||||
var branch = node.body[i];
|
||||
if (branch instanceof AST_Case) {
|
||||
if (!hit) {
|
||||
if (branch !== hit_stack[hit_index]) continue;
|
||||
hit_index++;
|
||||
}
|
||||
branch.expression = branch.expression.transform(scanner);
|
||||
if (side_effects || !replace_all) break;
|
||||
}
|
||||
}
|
||||
abort = true;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
function has_overlapping_symbol(fn, arg, fn_strict) {
|
||||
var found = false, scan_this = !(fn instanceof AST_Arrow);
|
||||
arg.walk(new TreeWalker(function(node, descend) {
|
||||
@@ -1334,18 +1382,49 @@ merge(Compressor.prototype, {
|
||||
hit_stack.pop();
|
||||
}
|
||||
|
||||
function find_stop(node, level) {
|
||||
function find_stop(node, level, write_only) {
|
||||
var parent = scanner.parent(level);
|
||||
if (parent instanceof AST_Binary) return node;
|
||||
if (parent instanceof AST_Assign) {
|
||||
if (write_only
|
||||
&& !(parent.left instanceof AST_PropAccess
|
||||
|| parent.left.name in lvalues)) {
|
||||
return find_stop(parent, level + 1, write_only);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_Binary) {
|
||||
if (write_only && (!lazy_op(parent.operator) || parent.left === node)) {
|
||||
return find_stop(parent, level + 1, write_only);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_Call) return node;
|
||||
if (parent instanceof AST_Case) return node;
|
||||
if (parent instanceof AST_Conditional) return node;
|
||||
if (parent instanceof AST_Definitions) return find_stop(parent, level + 1);
|
||||
if (parent instanceof AST_Exit) return node;
|
||||
if (parent instanceof AST_If) return node;
|
||||
if (parent instanceof AST_Conditional) {
|
||||
if (write_only && parent.condition === node) {
|
||||
return find_stop(parent, level + 1, write_only);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_Definitions) {
|
||||
return find_stop(parent, level + 1, true);
|
||||
}
|
||||
if (parent instanceof AST_Exit) {
|
||||
return write_only ? find_stop(parent, level + 1, write_only) : node;
|
||||
}
|
||||
if (parent instanceof AST_If) {
|
||||
if (write_only && parent.condition === node) {
|
||||
return find_stop(parent, level + 1, write_only);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_Sequence) return find_stop(parent, level + 1);
|
||||
if (parent instanceof AST_SimpleStatement) return find_stop(parent, level + 1);
|
||||
if (parent instanceof AST_Sequence) {
|
||||
return find_stop(parent, level + 1, parent.tail_node() !== node);
|
||||
}
|
||||
if (parent instanceof AST_SimpleStatement) {
|
||||
return find_stop(parent, level + 1, true);
|
||||
}
|
||||
if (parent instanceof AST_Switch) return node;
|
||||
if (parent instanceof AST_VarDef) return node;
|
||||
return null;
|
||||
@@ -1394,11 +1473,6 @@ merge(Compressor.prototype, {
|
||||
return lvalues;
|
||||
}
|
||||
|
||||
function lhs_or_def(node) {
|
||||
if (node instanceof AST_VarDef) return node.value && node.name;
|
||||
return is_lhs(node.left, node);
|
||||
}
|
||||
|
||||
function remove_candidate(expr) {
|
||||
if (expr.name instanceof AST_SymbolFunarg) {
|
||||
var iife = compressor.parent(), argnames = compressor.self().argnames;
|
||||
@@ -1437,31 +1511,25 @@ merge(Compressor.prototype, {
|
||||
return get_rvalue(expr).has_side_effects(compressor);
|
||||
}
|
||||
|
||||
function references_in_scope(def) {
|
||||
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return true;
|
||||
if (def.scope.get_defun_scope() !== scope) return false;
|
||||
return def.references.every(function(ref) {
|
||||
function may_modify(sym) {
|
||||
var def = sym.definition();
|
||||
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
|
||||
if (def.scope.get_defun_scope() !== scope) return true;
|
||||
return !all(def.references, function(ref) {
|
||||
return ref.scope.get_defun_scope() === scope;
|
||||
});
|
||||
}
|
||||
|
||||
function side_effects_external(node, lhs) {
|
||||
if (node instanceof AST_Assign) {
|
||||
return side_effects_external(node.left, true)
|
||||
|| side_effects_external(node.right);
|
||||
}
|
||||
if (node instanceof AST_Definitions) return false;
|
||||
if (node instanceof AST_Assign) return side_effects_external(node.left, true);
|
||||
if (node instanceof AST_Unary) return side_effects_external(node.expression, true);
|
||||
if (node instanceof AST_VarDef) return node.value && side_effects_external(node.value);
|
||||
if (lhs) {
|
||||
if (node instanceof AST_Dot) return side_effects_external(node.expression, true);
|
||||
if (node instanceof AST_Sub) {
|
||||
return side_effects_external(node.expression, true)
|
||||
|| side_effects_external(node.property);
|
||||
}
|
||||
if (node instanceof AST_Sub) return side_effects_external(node.expression, true);
|
||||
if (node instanceof AST_SymbolRef) return node.definition().scope !== scope;
|
||||
}
|
||||
return node.has_side_effects(compressor);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2291,6 +2359,8 @@ merge(Compressor.prototype, {
|
||||
"split",
|
||||
"substr",
|
||||
"substring",
|
||||
"toLowerCase",
|
||||
"toUpperCase",
|
||||
"trim",
|
||||
].concat(object_fns),
|
||||
};
|
||||
@@ -2843,8 +2913,13 @@ merge(Compressor.prototype, {
|
||||
return any(this.elements, compressor);
|
||||
});
|
||||
def(AST_Assign, function(compressor){
|
||||
return this.operator != "=" && this.left.may_throw(compressor)
|
||||
|| this.right.may_throw(compressor);
|
||||
if (this.right.may_throw(compressor)) return true;
|
||||
if (!compressor.has_directive("use strict")
|
||||
&& this.operator == "="
|
||||
&& this.left instanceof AST_SymbolRef) {
|
||||
return false;
|
||||
}
|
||||
return this.left.may_throw(compressor);
|
||||
});
|
||||
def(AST_Binary, function(compressor){
|
||||
return this.left.may_throw(compressor)
|
||||
@@ -3126,7 +3201,7 @@ merge(Compressor.prototype, {
|
||||
} else {
|
||||
var node_def = def.name.definition();;
|
||||
initializations.add(node_def.id, def.value);
|
||||
if (def.name.fixed_value() === def.value) {
|
||||
if (!node_def.chained && def.name.fixed_value() === def.value) {
|
||||
fixed_ids[node_def.id] = def;
|
||||
}
|
||||
}
|
||||
@@ -3374,7 +3449,7 @@ merge(Compressor.prototype, {
|
||||
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||
if (node instanceof AST_Assign) {
|
||||
node.right.walk(tw);
|
||||
if (node.left.fixed_value() === node.right) {
|
||||
if (!node_def.chained && node.left.fixed_value() === node.right) {
|
||||
fixed_ids[node_def.id] = node;
|
||||
}
|
||||
}
|
||||
@@ -5034,6 +5109,7 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("comparisons")) switch (self.operator) {
|
||||
case "===":
|
||||
case "!==":
|
||||
var is_strict_comparison = true;
|
||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||
(self.left.is_boolean() && self.right.is_boolean()) ||
|
||||
@@ -5043,8 +5119,12 @@ merge(Compressor.prototype, {
|
||||
// XXX: intentionally falling down to the next case
|
||||
case "==":
|
||||
case "!=":
|
||||
// void 0 == x => null == x
|
||||
if (!is_strict_comparison && is_undefined(self.left, compressor)) {
|
||||
self.left = make_node(AST_Null, self.left);
|
||||
}
|
||||
// "undefined" == typeof x => undefined === x
|
||||
if (compressor.option("typeofs")
|
||||
else if (compressor.option("typeofs")
|
||||
&& self.left instanceof AST_String
|
||||
&& self.left.value == "undefined"
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
@@ -5065,6 +5145,35 @@ merge(Compressor.prototype, {
|
||||
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
||||
}
|
||||
break;
|
||||
case "&&":
|
||||
case "||":
|
||||
var lhs = self.left;
|
||||
if (lhs.operator == self.operator) {
|
||||
lhs = lhs.right;
|
||||
}
|
||||
if (lhs instanceof AST_Binary
|
||||
&& lhs.operator == (self.operator == "&&" ? "!==" : "===")
|
||||
&& self.right instanceof AST_Binary
|
||||
&& lhs.operator == self.right.operator
|
||||
&& (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
|
||||
|| lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor))
|
||||
&& !lhs.right.has_side_effects(compressor)
|
||||
&& lhs.right.equivalent_to(self.right.right)) {
|
||||
var combined = make_node(AST_Binary, self, {
|
||||
operator: lhs.operator.slice(0, -1),
|
||||
left: make_node(AST_Null, self),
|
||||
right: lhs.right
|
||||
});
|
||||
if (lhs !== self.left) {
|
||||
combined = make_node(AST_Binary, self, {
|
||||
operator: self.operator,
|
||||
left: self.left.left,
|
||||
right: combined
|
||||
});
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (self.operator == "+" && compressor.in_boolean_context()) {
|
||||
var ll = self.left.evaluate(compressor);
|
||||
@@ -5521,7 +5630,7 @@ merge(Compressor.prototype, {
|
||||
var name_length = d.name.length;
|
||||
var overhead = 0;
|
||||
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||
overhead = (name_length + 2 + value_length) / (d.references.length - d.assignments);
|
||||
}
|
||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||
} else {
|
||||
@@ -5642,6 +5751,7 @@ merge(Compressor.prototype, {
|
||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||
if (is_reachable(def.scope, [ def ])) break;
|
||||
if (self.operator == "=") return self.right;
|
||||
def.fixed = false;
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: self.operator.slice(0, -1),
|
||||
left: self.left,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.3.9",
|
||||
"version": "3.3.10",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -24,13 +24,13 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.13.0",
|
||||
"commander": "~2.14.1",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~5.3.0",
|
||||
"acorn": "~5.4.1",
|
||||
"mocha": "~3.5.1",
|
||||
"semver": "~5.4.1"
|
||||
"semver": "~5.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/run-tests.js"
|
||||
|
||||
@@ -52,13 +52,8 @@ collapse_vars_side_effects_1: {
|
||||
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(i++), 7);
|
||||
}
|
||||
function f2() {
|
||||
var log = console.log.bind(console),
|
||||
s = "abcdef",
|
||||
i = 2,
|
||||
x = s.charAt(i++),
|
||||
y = s.charAt(i++),
|
||||
z = s.charAt(i++);
|
||||
log(x, i, y, z, 7);
|
||||
var s = "abcdef", i = 2;
|
||||
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(i++), 7);
|
||||
}
|
||||
function f3() {
|
||||
var s = "abcdef",
|
||||
@@ -72,7 +67,7 @@ collapse_vars_side_effects_1: {
|
||||
var i = 10,
|
||||
x = i += 2,
|
||||
y = i += 3;
|
||||
console.log.bind(console)(x, i += 4, y, i);
|
||||
console.log.bind(console)(x, i += 4, y, 19);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
@@ -4414,3 +4409,413 @@ unsafe_builtin: {
|
||||
}
|
||||
expect_stdout: "1 4"
|
||||
}
|
||||
|
||||
return_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
var a = c;
|
||||
if (b) return b;
|
||||
log(a);
|
||||
}
|
||||
f(false, 1);
|
||||
f(true, 2);
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
if (b) return b;
|
||||
log(c);
|
||||
}
|
||||
f(false, 1);
|
||||
f(true, 2);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
return_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
var a = c();
|
||||
if (b) return b;
|
||||
log(a);
|
||||
}
|
||||
f(false, function() { return 1 });
|
||||
f(true, function() { return 2 });
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
var a = c();
|
||||
if (b) return b;
|
||||
log(a);
|
||||
}
|
||||
f(false, function() { return 1 });
|
||||
f(true, function() { return 2 });
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
return_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
var a = b <<= c;
|
||||
if (b) return b;
|
||||
log(a);
|
||||
}
|
||||
f(false, 1);
|
||||
f(true, 2);
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
function f(b, c) {
|
||||
var a = b <<= c;
|
||||
if (b) return b;
|
||||
log(a);
|
||||
}
|
||||
f(false, 1);
|
||||
f(true, 2);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
return_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(function(b) {
|
||||
a = "PASS";
|
||||
return;
|
||||
b(a);
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(function(b) {
|
||||
a = "PASS";
|
||||
return;
|
||||
b(a);
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2858: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b;
|
||||
(function() {
|
||||
function f() {
|
||||
a++;
|
||||
}
|
||||
f();
|
||||
var c = f();
|
||||
var a = void 0;
|
||||
c || (b = a);
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b;
|
||||
(function() {
|
||||
function f() {
|
||||
a++;
|
||||
}
|
||||
f();
|
||||
var c = f();
|
||||
var a = void 0;
|
||||
c || (b = a);
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
cond_branch_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f1(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
if (b) b++;
|
||||
log(a, b);
|
||||
}
|
||||
function f2(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
b && b++;
|
||||
log(a, b);
|
||||
}
|
||||
function f3(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
b ? b++ : b--;
|
||||
log(a, b);
|
||||
}
|
||||
f1(1, 2);
|
||||
f2(3, 4);
|
||||
f3(5, 6);
|
||||
}
|
||||
expect: {
|
||||
function f1(b, c) {
|
||||
if (b) b++;
|
||||
(0, console.log)(++c, b);
|
||||
}
|
||||
function f2(b, c) {
|
||||
b && b++,
|
||||
(0, console.log)(++c, b);
|
||||
}
|
||||
function f3(b, c) {
|
||||
b ? b++ : b--,
|
||||
(0, console.log)(++c, b);
|
||||
}
|
||||
f1(1, 2),
|
||||
f2(3, 4),
|
||||
f3(5, 6);
|
||||
}
|
||||
expect_stdout: [
|
||||
"3 2",
|
||||
"5 4",
|
||||
"7 6",
|
||||
]
|
||||
}
|
||||
|
||||
cond_branch_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f1(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
if (b) b += a;
|
||||
log(a, b);
|
||||
}
|
||||
function f2(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
b && (b += a);
|
||||
log(a, b);
|
||||
}
|
||||
function f3(b, c) {
|
||||
var log = console.log;
|
||||
var a = ++c;
|
||||
b ? b += a : b--;
|
||||
log(a, b);
|
||||
}
|
||||
f1(1, 2);
|
||||
f2(3, 4);
|
||||
f3(5, 6);
|
||||
}
|
||||
expect: {
|
||||
function f1(b, c) {
|
||||
var a = ++c;
|
||||
if (b) b += a;
|
||||
(0, console.log)(a, b);
|
||||
}
|
||||
function f2(b, c) {
|
||||
var a = ++c;
|
||||
b && (b += a),
|
||||
(0, console.log)(a, b);
|
||||
}
|
||||
function f3(b, c) {
|
||||
var a = ++c;
|
||||
b ? b += a : b--,
|
||||
(0, console.log)(a, b);
|
||||
}
|
||||
f1(1, 2),
|
||||
f2(3, 4),
|
||||
f3(5, 6);
|
||||
}
|
||||
expect_stdout: [
|
||||
"3 4",
|
||||
"5 8",
|
||||
"7 12",
|
||||
]
|
||||
}
|
||||
|
||||
cond_branch_switch: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
if (c = 1 + c, 0) switch (c = 1 + c) {
|
||||
}
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
if (c = 1 + c, 0) switch (c = 1 + c) {
|
||||
}
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2873_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1, c = 0;
|
||||
do {
|
||||
c++;
|
||||
if (!--b) break;
|
||||
c = 1 + c;
|
||||
} while (0);
|
||||
console.log(b, c);
|
||||
}
|
||||
expect: {
|
||||
var b = 1, c = 0;
|
||||
do {
|
||||
c++;
|
||||
if (!--b) break;
|
||||
c = 1 + c;
|
||||
} while (0);
|
||||
console.log(b, c);
|
||||
}
|
||||
expect_stdout: "0 1"
|
||||
}
|
||||
|
||||
issue_2873_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1, c = 0;
|
||||
do {
|
||||
c++;
|
||||
if (!--b) continue;
|
||||
c = 1 + c;
|
||||
} while (0);
|
||||
console.log(b, c);
|
||||
}
|
||||
expect: {
|
||||
var b = 1, c = 0;
|
||||
do {
|
||||
c++;
|
||||
if (!--b) continue;
|
||||
c = 1 + c;
|
||||
} while (0);
|
||||
console.log(b, c);
|
||||
}
|
||||
expect_stdout: "0 1"
|
||||
}
|
||||
|
||||
issue_2878: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function (a, b) {
|
||||
function f2() {
|
||||
if (a) c++;
|
||||
}
|
||||
b = f2();
|
||||
a = 1;
|
||||
b && b.b;
|
||||
f2();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function (a, b) {
|
||||
function f2() {
|
||||
if (a) c++;
|
||||
}
|
||||
b = f2(),
|
||||
a = 1,
|
||||
b && b.b,
|
||||
f2();
|
||||
})(),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2891_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS", b;
|
||||
try {
|
||||
b = c.p = 0;
|
||||
a = "FAIL";
|
||||
b();
|
||||
} catch (e) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b;
|
||||
try {
|
||||
b = c.p = 0;
|
||||
a = "FAIL";
|
||||
b();
|
||||
} catch (e) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2891_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = "PASS", b;
|
||||
try {
|
||||
b = c = 0;
|
||||
a = "FAIL";
|
||||
b();
|
||||
} catch (e) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var a = "PASS", b;
|
||||
try {
|
||||
b = c = 0;
|
||||
a = "FAIL";
|
||||
b();
|
||||
} catch (e) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -112,3 +112,206 @@ self_comparison_2: {
|
||||
}
|
||||
expect_stdout: "false true"
|
||||
}
|
||||
|
||||
issue_2857_1: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a) {
|
||||
a === undefined || a === null;
|
||||
a === undefined || a !== null;
|
||||
a !== undefined || a === null;
|
||||
a !== undefined || a !== null;
|
||||
a === undefined && a === null;
|
||||
a === undefined && a !== null;
|
||||
a !== undefined && a === null;
|
||||
a !== undefined && a !== null;
|
||||
}
|
||||
function f2(a) {
|
||||
a === null || a === undefined;
|
||||
a === null || a !== undefined;
|
||||
a !== null || a === undefined;
|
||||
a !== null || a !== undefined;
|
||||
a === null && a === undefined;
|
||||
a === null && a !== undefined;
|
||||
a !== null && a === undefined;
|
||||
a !== null && a !== undefined;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f1(a) {
|
||||
null == a;
|
||||
void 0 === a || null !== a;
|
||||
void 0 !== a || null === a;
|
||||
void 0 !== a || null !== a;
|
||||
void 0 === a && null === a;
|
||||
void 0 === a && null !== a;
|
||||
void 0 !== a && null === a;
|
||||
null != a;
|
||||
}
|
||||
function f2(a) {
|
||||
null == a;
|
||||
null === a || void 0 !== a;
|
||||
null !== a || void 0 === a;
|
||||
null !== a || void 0 !== a;
|
||||
null === a && void 0 === a;
|
||||
null === a && void 0 !== a;
|
||||
null !== a && void 0 === a;
|
||||
null != a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2857_2: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, p) {
|
||||
a === undefined || a === null || p;
|
||||
a === undefined || a !== null || p;
|
||||
a !== undefined || a === null || p;
|
||||
a !== undefined || a !== null || p;
|
||||
a === undefined && a === null || p;
|
||||
a === undefined && a !== null || p;
|
||||
a !== undefined && a === null || p;
|
||||
a !== undefined && a !== null || p;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a, p) {
|
||||
null == a || p;
|
||||
void 0 === a || null !== a || p;
|
||||
void 0 !== a || null === a || p;
|
||||
void 0 !== a || null !== a || p;
|
||||
void 0 === a && null === a || p;
|
||||
void 0 === a && null !== a || p;
|
||||
void 0 !== a && null === a || p;
|
||||
null != a || p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2857_3: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, p) {
|
||||
a === undefined || a === null && p;
|
||||
a === undefined || a !== null && p;
|
||||
a !== undefined || a === null && p;
|
||||
a !== undefined || a !== null && p;
|
||||
a === undefined && a === null && p;
|
||||
a === undefined && a !== null && p;
|
||||
a !== undefined && a === null && p;
|
||||
a !== undefined && a !== null && p;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a, p) {
|
||||
void 0 === a || null === a && p;
|
||||
void 0 === a || null !== a && p;
|
||||
void 0 !== a || null === a && p;
|
||||
void 0 !== a || null !== a && p;
|
||||
void 0 === a && null === a && p;
|
||||
void 0 === a && null !== a && p;
|
||||
void 0 !== a && null === a && p;
|
||||
null != a && p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2857_4: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, p) {
|
||||
p || a === undefined || a === null;
|
||||
p || a === undefined || a !== null;
|
||||
p || a !== undefined || a === null;
|
||||
p || a !== undefined || a !== null;
|
||||
p || a === undefined && a === null;
|
||||
p || a === undefined && a !== null;
|
||||
p || a !== undefined && a === null;
|
||||
p || a !== undefined && a !== null;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a, p) {
|
||||
p || null == a;
|
||||
p || void 0 === a || null !== a;
|
||||
p || void 0 !== a || null === a;
|
||||
p || void 0 !== a || null !== a;
|
||||
p || void 0 === a && null === a;
|
||||
p || void 0 === a && null !== a;
|
||||
p || void 0 !== a && null === a;
|
||||
p || null != a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2857_5: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, p) {
|
||||
p && a === undefined || a === null;
|
||||
p && a === undefined || a !== null;
|
||||
p && a !== undefined || a === null;
|
||||
p && a !== undefined || a !== null;
|
||||
p && a === undefined && a === null;
|
||||
p && a === undefined && a !== null;
|
||||
p && a !== undefined && a === null;
|
||||
p && a !== undefined && a !== null;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a, p) {
|
||||
p && void 0 === a || null === a;
|
||||
p && void 0 === a || null !== a;
|
||||
p && void 0 !== a || null === a;
|
||||
p && void 0 !== a || null !== a;
|
||||
p && void 0 === a && null === a;
|
||||
p && void 0 === a && null !== a;
|
||||
p && void 0 !== a && null === a;
|
||||
p && null != a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_2857_6: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
if (({}).b === undefined || {}.b === null)
|
||||
return a.b !== undefined && a.b !== null;
|
||||
}
|
||||
console.log(f({
|
||||
a: [ null ],
|
||||
get b() {
|
||||
return this.a.shift();
|
||||
}
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
if (null == {}.b)
|
||||
return void 0 !== a.b && null !== a.b;
|
||||
}
|
||||
console.log(f({
|
||||
a: [ null ],
|
||||
get b() {
|
||||
return this.a.shift();
|
||||
}
|
||||
}));
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
@@ -1178,3 +1178,41 @@ unsafe_builtin: {
|
||||
z;
|
||||
}
|
||||
}
|
||||
|
||||
issue_2860_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a ^= 1;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1 ^ a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2860_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a ^= 1;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -1467,3 +1467,58 @@ issue_2822: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
string_case: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log("İ".toLowerCase().charCodeAt(0));
|
||||
console.log("I".toLowerCase().charCodeAt(0));
|
||||
console.log("Ş".toLowerCase().charCodeAt(0));
|
||||
console.log("Ğ".toLowerCase().charCodeAt(0));
|
||||
console.log("Ü".toLowerCase().charCodeAt(0));
|
||||
console.log("Ö".toLowerCase().charCodeAt(0));
|
||||
console.log("Ç".toLowerCase().charCodeAt(0));
|
||||
console.log("i".toUpperCase().charCodeAt(0));
|
||||
console.log("ı".toUpperCase().charCodeAt(0));
|
||||
console.log("ş".toUpperCase().charCodeAt(0));
|
||||
console.log("ğ".toUpperCase().charCodeAt(0));
|
||||
console.log("ü".toUpperCase().charCodeAt(0));
|
||||
console.log("ö".toUpperCase().charCodeAt(0));
|
||||
console.log("ç".toUpperCase().charCodeAt(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(105);
|
||||
console.log(105);
|
||||
console.log(351);
|
||||
console.log(287);
|
||||
console.log(252);
|
||||
console.log(246);
|
||||
console.log(231);
|
||||
console.log(73);
|
||||
console.log(73);
|
||||
console.log(350);
|
||||
console.log(286);
|
||||
console.log(220);
|
||||
console.log(214);
|
||||
console.log(199);
|
||||
}
|
||||
expect_stdout: [
|
||||
"105",
|
||||
"105",
|
||||
"351",
|
||||
"287",
|
||||
"252",
|
||||
"246",
|
||||
"231",
|
||||
"73",
|
||||
"73",
|
||||
"350",
|
||||
"286",
|
||||
"220",
|
||||
"214",
|
||||
"199",
|
||||
]
|
||||
}
|
||||
|
||||
37
test/compress/issue-2871.js
Normal file
37
test/compress/issue-2871.js
Normal file
@@ -0,0 +1,37 @@
|
||||
comparison_with_undefined: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
}
|
||||
input: {
|
||||
a == undefined;
|
||||
a != undefined;
|
||||
a === undefined;
|
||||
a !== undefined;
|
||||
|
||||
undefined == a;
|
||||
undefined != a;
|
||||
undefined === a;
|
||||
undefined !== a;
|
||||
|
||||
void 0 == a;
|
||||
void 0 != a;
|
||||
void 0 === a;
|
||||
void 0 !== a;
|
||||
}
|
||||
expect: {
|
||||
null == a;
|
||||
null != a;
|
||||
void 0 === a;
|
||||
void 0 !== a;
|
||||
|
||||
null == a;
|
||||
null != a;
|
||||
void 0 === a;
|
||||
void 0 !== a;
|
||||
|
||||
null == a;
|
||||
null != a;
|
||||
void 0 === a;
|
||||
void 0 !== a;
|
||||
}
|
||||
}
|
||||
@@ -76,14 +76,12 @@ modified: {
|
||||
console.log(a + 1);
|
||||
console.log(b + 1);
|
||||
}
|
||||
|
||||
function f1() {
|
||||
var a = 1, b = 2;
|
||||
--b;
|
||||
console.log(a + 1);
|
||||
console.log(b + 1);
|
||||
}
|
||||
|
||||
function f2() {
|
||||
var a = 1, b = 2, c = 3;
|
||||
b = c;
|
||||
@@ -92,7 +90,6 @@ modified: {
|
||||
console.log(a + c);
|
||||
console.log(a + b + c);
|
||||
}
|
||||
|
||||
function f3() {
|
||||
var a = 1, b = 2, c = 3;
|
||||
b *= c;
|
||||
@@ -101,7 +98,6 @@ modified: {
|
||||
console.log(a + c);
|
||||
console.log(a + b + c);
|
||||
}
|
||||
|
||||
function f4() {
|
||||
var a = 1, b = 2, c = 3;
|
||||
if (a) {
|
||||
@@ -114,28 +110,26 @@ modified: {
|
||||
console.log(a + c);
|
||||
console.log(a + b + c);
|
||||
}
|
||||
|
||||
function f5(a) {
|
||||
B = a;
|
||||
console.log(A ? 'yes' : 'no');
|
||||
console.log(B ? 'yes' : 'no');
|
||||
console.log(typeof A ? "yes" : "no");
|
||||
console.log(typeof B ? "yes" : "no");
|
||||
}
|
||||
f0(), f1(), f2(), f3(), f4(), f5();
|
||||
}
|
||||
expect: {
|
||||
function f0() {
|
||||
var b = 2;
|
||||
b++;
|
||||
console.log(2);
|
||||
console.log(b + 1);
|
||||
console.log(4);
|
||||
}
|
||||
|
||||
function f1() {
|
||||
var b = 2;
|
||||
--b;
|
||||
console.log(2);
|
||||
console.log(b + 1);
|
||||
console.log(2);
|
||||
}
|
||||
|
||||
function f2() {
|
||||
3;
|
||||
console.log(4);
|
||||
@@ -143,16 +137,14 @@ modified: {
|
||||
console.log(4);
|
||||
console.log(7);
|
||||
}
|
||||
|
||||
function f3() {
|
||||
var b = 2;
|
||||
b *= 3;
|
||||
console.log(1 + b);
|
||||
console.log(b + 3);
|
||||
console.log(7);
|
||||
console.log(9);
|
||||
console.log(4);
|
||||
console.log(1 + b + 3);
|
||||
console.log(10);
|
||||
}
|
||||
|
||||
function f4() {
|
||||
var b = 2, c = 3;
|
||||
b = c;
|
||||
@@ -161,13 +153,33 @@ modified: {
|
||||
console.log(1 + c);
|
||||
console.log(1 + b + c);
|
||||
}
|
||||
|
||||
function f5(a) {
|
||||
B = a;
|
||||
console.log(A ? 'yes' : 'no');
|
||||
console.log(B ? 'yes' : 'no');
|
||||
console.log(typeof A ? "yes" : "no");
|
||||
console.log(typeof B ? "yes" : "no");
|
||||
}
|
||||
f0(), f1(), f2(), f3(), f4(), f5();
|
||||
}
|
||||
expect_stdout: [
|
||||
"2",
|
||||
"4",
|
||||
"2",
|
||||
"2",
|
||||
"4",
|
||||
"6",
|
||||
"4",
|
||||
"7",
|
||||
"7",
|
||||
"9",
|
||||
"4",
|
||||
"10",
|
||||
"4",
|
||||
"6",
|
||||
"4",
|
||||
"7",
|
||||
"yes",
|
||||
"yes",
|
||||
]
|
||||
}
|
||||
|
||||
unsafe_evaluate: {
|
||||
@@ -745,7 +757,7 @@ iife: {
|
||||
expect: {
|
||||
!function(a, b, c) {
|
||||
b++;
|
||||
console.log(0, 1 * b, 5);
|
||||
console.log(0, 3, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -766,7 +778,7 @@ iife_new: {
|
||||
expect: {
|
||||
var A = new function(a, b, c) {
|
||||
b++;
|
||||
console.log(0, 1 * b, 5);
|
||||
console.log(0, 3, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -5973,3 +5985,141 @@ issue_2836: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
lvalues_def_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
var a = b++, b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a = b++;
|
||||
b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "1 NaN"
|
||||
}
|
||||
|
||||
lvalues_def_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
var a = b += 1, b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a = b += 1;
|
||||
b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "2 NaN"
|
||||
}
|
||||
|
||||
chained_assignments: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var a = [0x5e, 0xad, 0xbe, 0xef];
|
||||
var b = 0;
|
||||
b |= a[0];
|
||||
b <<= 8;
|
||||
b |= a[1];
|
||||
b <<= 8;
|
||||
b |= a[2];
|
||||
b <<= 8;
|
||||
b |= a[3];
|
||||
return b;
|
||||
}
|
||||
console.log(f().toString(16));
|
||||
}
|
||||
expect: {
|
||||
console.log("5eadbeef");
|
||||
}
|
||||
expect_stdout: "5eadbeef"
|
||||
}
|
||||
|
||||
issue_2860_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a ^= 1;
|
||||
a ^= 2;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1 ^ a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2860_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a ^= 1;
|
||||
a ^= 2;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2869: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function f(a) {
|
||||
var a;
|
||||
if (!f) a = 0;
|
||||
if (a) c = "PASS";
|
||||
})(1);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function f(a) {
|
||||
var a;
|
||||
if (!f) a = 0;
|
||||
if (a) c = "PASS";
|
||||
})(1);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1024,7 +1024,6 @@ function log_suspects(minify_options, component) {
|
||||
}
|
||||
|
||||
function log_rename(options) {
|
||||
if (!options.rename) return;
|
||||
var m = JSON.parse(JSON.stringify(options));
|
||||
m.rename = false;
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
|
||||
Reference in New Issue
Block a user