Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02cc4a0d03 | ||
|
|
4e06e1ca34 | ||
|
|
644f65feca | ||
|
|
8504a4ea0e | ||
|
|
10c1a78772 | ||
|
|
a6a0319f1c | ||
|
|
d1b2ecec27 | ||
|
|
552be61c4d | ||
|
|
dcfc4aca5b | ||
|
|
4027f87717 | ||
|
|
910799ca99 | ||
|
|
4bd36dc8da | ||
|
|
ab15c40770 | ||
|
|
fe65ce9658 | ||
|
|
d6fd18d0b0 | ||
|
|
0d17c5b0fa | ||
|
|
5b20bad4b3 | ||
|
|
765a06340f | ||
|
|
5045e140b1 | ||
|
|
10648c9af6 | ||
|
|
87e67ec299 | ||
|
|
61a0dad9fe | ||
|
|
3e2c51a4da | ||
|
|
0e29ad5eb9 |
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -14,13 +14,17 @@ jobs:
|
||||
TYPE: ${{ matrix.script }}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- shell: bash
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: tmp
|
||||
key: tmp ${{ matrix.script }}
|
||||
- name: Perform tests
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
. ~/.nvs/nvs.sh
|
||||
nvs --version
|
||||
nvs add node/$NODE
|
||||
nvs use node/$NODE
|
||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
. ~/.nvs/nvs.sh --version
|
||||
nvs add $NODE
|
||||
nvs use $NODE
|
||||
node --version
|
||||
npm --version --no-update-notifier
|
||||
npm install --no-audit --no-optional --no-save --no-update-notifier
|
||||
|
||||
8
.github/workflows/ufuzz.yml
vendored
8
.github/workflows/ufuzz.yml
vendored
@@ -12,11 +12,11 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- shell: bash
|
||||
- name: Perform fuzzing
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
. ~/.nvs/nvs.sh
|
||||
nvs --version
|
||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
. ~/.nvs/nvs.sh --version
|
||||
nvs add node
|
||||
nvs use node
|
||||
node --version
|
||||
|
||||
46
.travis.yml
46
.travis.yml
@@ -1,46 +0,0 @@
|
||||
cache:
|
||||
directories: tmp
|
||||
language: shell
|
||||
matrix:
|
||||
fast_finish: true
|
||||
env:
|
||||
- NODE=0.10 TYPE=compress
|
||||
- NODE=0.10 TYPE=mocha
|
||||
- NODE=0.10 TYPE=release/benchmark
|
||||
- NODE=0.10 TYPE=release/jetstream
|
||||
- NODE=0.12 TYPE=compress
|
||||
- NODE=0.12 TYPE=mocha
|
||||
- NODE=0.12 TYPE=release/benchmark
|
||||
- NODE=0.12 TYPE=release/jetstream
|
||||
- NODE=4 TYPE=compress
|
||||
- NODE=4 TYPE=mocha
|
||||
- NODE=4 TYPE=release/benchmark
|
||||
- NODE=4 TYPE=release/jetstream
|
||||
- NODE=6 TYPE=compress
|
||||
- NODE=6 TYPE=mocha
|
||||
- NODE=6 TYPE=release/benchmark
|
||||
- NODE=6 TYPE=release/jetstream
|
||||
- NODE=8 TYPE=compress
|
||||
- NODE=8 TYPE=mocha
|
||||
- NODE=8 TYPE=release/benchmark
|
||||
- NODE=8 TYPE=release/jetstream
|
||||
- NODE=10 TYPE=compress
|
||||
- NODE=10 TYPE=mocha
|
||||
- NODE=10 TYPE=release/benchmark
|
||||
- NODE=10 TYPE=release/jetstream
|
||||
- NODE=latest TYPE=compress
|
||||
- NODE=latest TYPE=mocha
|
||||
- NODE=latest TYPE=release/benchmark
|
||||
- NODE=latest TYPE=release/jetstream
|
||||
before_install:
|
||||
- git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
- . ~/.nvs/nvs.sh
|
||||
- nvs --version
|
||||
install:
|
||||
- nvs add node/$NODE
|
||||
- nvs use node/$NODE
|
||||
- node --version
|
||||
- npm --version --no-update-notifier
|
||||
- npm install --no-audit --no-optional --no-save --no-update-notifier
|
||||
script:
|
||||
- node test/$TYPE
|
||||
@@ -631,7 +631,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
|
||||
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
|
||||
|
||||
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
|
||||
- `evaluate` (default: `true`) -- Evaluate expression for shorter constant
|
||||
representation. Pass `"eager"` to always replace function calls whenever
|
||||
possible, or a positive integer to specify an upper bound for each individual
|
||||
evaluation in number of characters.
|
||||
|
||||
- `expression` (default: `false`) -- Pass `true` to preserve completion values
|
||||
from terminal statements without `return`, e.g. in bookmarklets.
|
||||
|
||||
71
appveyor.yml
71
appveyor.yml
@@ -1,74 +1,5 @@
|
||||
build: off
|
||||
cache:
|
||||
- tmp
|
||||
matrix:
|
||||
fast_finish: true
|
||||
environment:
|
||||
matrix:
|
||||
- NODE: 0.10
|
||||
TYPE: compress
|
||||
- NODE: 0.10
|
||||
TYPE: mocha
|
||||
- NODE: 0.10
|
||||
TYPE: release/benchmark
|
||||
- NODE: 0.10
|
||||
TYPE: release/jetstream
|
||||
- NODE: 0.12
|
||||
TYPE: compress
|
||||
- NODE: 0.12
|
||||
TYPE: mocha
|
||||
- NODE: 0.12
|
||||
TYPE: release/benchmark
|
||||
- NODE: 0.12
|
||||
TYPE: release/jetstream
|
||||
- NODE: 4
|
||||
TYPE: compress
|
||||
- NODE: 4
|
||||
TYPE: mocha
|
||||
- NODE: 4
|
||||
TYPE: release/benchmark
|
||||
- NODE: 4
|
||||
TYPE: release/jetstream
|
||||
- NODE: 6
|
||||
TYPE: compress
|
||||
- NODE: 6
|
||||
TYPE: mocha
|
||||
- NODE: 6
|
||||
TYPE: release/benchmark
|
||||
- NODE: 6
|
||||
TYPE: release/jetstream
|
||||
- NODE: 8
|
||||
TYPE: compress
|
||||
- NODE: 8
|
||||
TYPE: mocha
|
||||
- NODE: 8
|
||||
TYPE: release/benchmark
|
||||
- NODE: 8
|
||||
TYPE: release/jetstream
|
||||
- NODE: 10
|
||||
TYPE: compress
|
||||
- NODE: 10
|
||||
TYPE: mocha
|
||||
- NODE: 10
|
||||
TYPE: release/benchmark
|
||||
- NODE: 10
|
||||
TYPE: release/jetstream
|
||||
- NODE: latest
|
||||
TYPE: compress
|
||||
- NODE: latest
|
||||
TYPE: mocha
|
||||
- NODE: latest
|
||||
TYPE: release/benchmark
|
||||
- NODE: latest
|
||||
TYPE: release/jetstream
|
||||
install:
|
||||
- git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git %LOCALAPPDATA%\nvs
|
||||
- set PATH=%LOCALAPPDATA%\nvs;%PATH%
|
||||
- nvs --version
|
||||
- nvs add node/%NODE%
|
||||
- nvs use node/%NODE%
|
||||
- node --version
|
||||
- npm --version --no-update-notifier
|
||||
- npm install --no-audit --no-optional --no-save --no-update-notifier
|
||||
test_script:
|
||||
- node test/%TYPE%
|
||||
- echo No longer in use
|
||||
|
||||
453
lib/compress.js
453
lib/compress.js
@@ -96,6 +96,8 @@ function Compressor(options, false_by_default) {
|
||||
unsafe_undefined: false,
|
||||
unused : !false_by_default,
|
||||
}, true);
|
||||
var evaluate = this.options["evaluate"];
|
||||
this.eval_threshold = /eager/.test(evaluate) ? 1 / 0 : +evaluate;
|
||||
var global_defs = this.options["global_defs"];
|
||||
if (typeof global_defs == "object") for (var key in global_defs) {
|
||||
if (/^@/.test(key) && HOP(global_defs, key)) {
|
||||
@@ -860,13 +862,9 @@ merge(Compressor.prototype, {
|
||||
|
||||
AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||
var tw = new TreeWalker(compressor.option("reduce_vars") ? function(node, descend) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
reset_flags(node);
|
||||
return node.reduce_vars(tw, descend, compressor);
|
||||
} : function(node) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
});
|
||||
} : reset_flags);
|
||||
// Flow control for visiting `AST_Defun`s
|
||||
tw.defun_ids = Object.create(null);
|
||||
tw.defun_visited = Object.create(null);
|
||||
@@ -879,6 +877,12 @@ merge(Compressor.prototype, {
|
||||
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||
tw.safe_ids = Object.create(null);
|
||||
this.walk(tw);
|
||||
|
||||
function reset_flags(node) {
|
||||
node._squeezed = false;
|
||||
node._optimized = false;
|
||||
if (node instanceof AST_Scope) delete node._var_names;
|
||||
}
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("fixed_value", function(final) {
|
||||
@@ -1090,7 +1094,7 @@ merge(Compressor.prototype, {
|
||||
scope = node;
|
||||
break;
|
||||
} else if (node instanceof AST_Try) {
|
||||
in_try = true;
|
||||
in_try = node;
|
||||
}
|
||||
} while (node = compressor.parent(level++));
|
||||
}
|
||||
@@ -1176,7 +1180,6 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
// These node types have child nodes that execute sequentially,
|
||||
// but are otherwise not safe to scan into or beyond them.
|
||||
var sym;
|
||||
if (is_last_node(node, parent) || may_throw(node)) {
|
||||
stop_after = node;
|
||||
if (node instanceof AST_Scope) abort = true;
|
||||
@@ -1235,7 +1238,7 @@ merge(Compressor.prototype, {
|
||||
var lvalues = get_lvalues(candidate);
|
||||
var lhs_local = is_lhs_local(lhs);
|
||||
if (!side_effects) side_effects = value_has_side_effects(candidate);
|
||||
var replace_all = replace_all_symbols();
|
||||
var replace_all = replace_all_symbols(candidate);
|
||||
var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) {
|
||||
return node.has_side_effects(compressor);
|
||||
} : side_effects_external : return_false;
|
||||
@@ -1283,6 +1286,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
branch.expression = branch.expression.transform(scanner);
|
||||
if (!replace_all) break;
|
||||
scan_rhs = false;
|
||||
}
|
||||
}
|
||||
abort = true;
|
||||
@@ -1312,6 +1316,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function in_conditional(node, parent) {
|
||||
if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
|
||||
if (parent instanceof AST_Case) return parent.expression !== node;
|
||||
if (parent instanceof AST_Conditional) return parent.condition !== node;
|
||||
return parent instanceof AST_If && parent.condition !== node;
|
||||
}
|
||||
@@ -1319,6 +1324,10 @@ merge(Compressor.prototype, {
|
||||
function is_last_node(node, parent) {
|
||||
if (node instanceof AST_Call) return true;
|
||||
if (node instanceof AST_Exit) {
|
||||
if (in_try) {
|
||||
if (in_try.bfinally) return true;
|
||||
if (in_try.bcatch && node instanceof AST_Throw) return true;
|
||||
}
|
||||
return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
|
||||
}
|
||||
if (node instanceof AST_Function) {
|
||||
@@ -1477,19 +1486,43 @@ merge(Compressor.prototype, {
|
||||
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_Definitions) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Exit) return node;
|
||||
if (parent instanceof AST_If) return node;
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_PropAccess) 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 (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Switch) return node;
|
||||
if (parent instanceof AST_Unary) return node;
|
||||
if (parent instanceof AST_VarDef) return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
function find_stop_unused(node, level) {
|
||||
var parent = scanner.parent(level);
|
||||
if (is_last_node(node, parent)) return node;
|
||||
if (in_conditional(node, parent)) return node;
|
||||
if (parent instanceof AST_Assign) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Binary) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Call) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Case) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Conditional) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_If) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_PropAccess) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Sequence) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Switch) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_Unary) return find_stop_unused(parent, level + 1);
|
||||
if (parent instanceof AST_VarDef) return find_stop_unused(parent, level + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
function mangleable_var(var_def) {
|
||||
var value = var_def.value;
|
||||
if (!(value instanceof AST_SymbolRef)) return;
|
||||
@@ -1656,16 +1689,21 @@ merge(Compressor.prototype, {
|
||||
return get_rvalue(expr).has_side_effects(compressor);
|
||||
}
|
||||
|
||||
function replace_all_symbols() {
|
||||
function replace_all_symbols(expr) {
|
||||
if (expr instanceof AST_Unary) return false;
|
||||
if (side_effects) return false;
|
||||
if (value_def) return true;
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
var def = lhs.definition();
|
||||
if (def.references.length - def.replaced == (candidate instanceof AST_VarDef ? 1 : 2)) {
|
||||
return true;
|
||||
}
|
||||
if (!(lhs instanceof AST_SymbolRef)) return false;
|
||||
var referenced;
|
||||
if (expr instanceof AST_VarDef) {
|
||||
referenced = 1;
|
||||
} else if (expr.operator == "=") {
|
||||
referenced = 2;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
var def = lhs.definition();
|
||||
return def.references.length - def.replaced == referenced;
|
||||
}
|
||||
|
||||
function symbol_in_lvalues(sym, parent) {
|
||||
@@ -2646,22 +2684,21 @@ merge(Compressor.prototype, {
|
||||
node.DEFMETHOD("_find_defs", func);
|
||||
});
|
||||
|
||||
function best_of_expression(ast1, ast2) {
|
||||
return ast1.print_to_string().length >
|
||||
ast2.print_to_string().length
|
||||
? ast2 : ast1;
|
||||
function best_of_expression(ast1, ast2, threshold) {
|
||||
var delta = ast2.print_to_string().length - ast1.print_to_string().length;
|
||||
return delta < (threshold || 0) ? ast2 : ast1;
|
||||
}
|
||||
|
||||
function best_of_statement(ast1, ast2) {
|
||||
function best_of_statement(ast1, ast2, threshold) {
|
||||
return best_of_expression(make_node(AST_SimpleStatement, ast1, {
|
||||
body: ast1
|
||||
}), make_node(AST_SimpleStatement, ast2, {
|
||||
body: ast2
|
||||
})).body;
|
||||
}), threshold).body;
|
||||
}
|
||||
|
||||
function best_of(compressor, ast1, ast2) {
|
||||
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2);
|
||||
function best_of(compressor, ast1, ast2, threshold) {
|
||||
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2, threshold);
|
||||
}
|
||||
|
||||
function convert_to_predicate(obj) {
|
||||
@@ -2670,6 +2707,13 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
|
||||
function try_evaluate(compressor, node) {
|
||||
var ev = node.evaluate(compressor);
|
||||
if (ev === node) return node;
|
||||
ev = make_node_from_constant(ev, node).optimize(compressor);
|
||||
return best_of(compressor, node, ev, compressor.eval_threshold);
|
||||
}
|
||||
|
||||
var object_fns = [
|
||||
"constructor",
|
||||
"toString",
|
||||
@@ -2881,6 +2925,7 @@ merge(Compressor.prototype, {
|
||||
if (!non_converting_binary[this.operator]) depth++;
|
||||
var left = this.left._eval(compressor, cached, depth);
|
||||
if (left === this.left) return this;
|
||||
if (this.operator == (left ? "||" : "&&")) return left;
|
||||
var right = this.right._eval(compressor, cached, depth);
|
||||
if (right === this.right) return this;
|
||||
var result;
|
||||
@@ -2914,7 +2959,8 @@ merge(Compressor.prototype, {
|
||||
&& typeof result == "number"
|
||||
&& (this.operator == "+" || this.operator == "-")) {
|
||||
var digits = Math.max(0, decimals(left), decimals(right));
|
||||
if (digits < 21) return +result.toFixed(digits);
|
||||
// 53-bit significand => 15.95 decimal places
|
||||
if (digits < 16) return +result.toFixed(digits);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -3031,15 +3077,15 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_Call, function(compressor, cached, depth) {
|
||||
var exp = this.expression;
|
||||
if (exp instanceof AST_SymbolRef) {
|
||||
var fn = exp.fixed_value();
|
||||
if (!(fn instanceof AST_Lambda)) return this;
|
||||
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||
if (fn instanceof AST_Lambda) {
|
||||
if (fn.evaluating) return this;
|
||||
if (fn.name && fn.name.definition().recursive_refs > 0) return this;
|
||||
if (fn.body.length != 1 || !fn.is_constant_expression()) return this;
|
||||
var stat = fn.body[0];
|
||||
if (!(stat instanceof AST_Return)) return this;
|
||||
var args = eval_args(this.args);
|
||||
if (!args) return this;
|
||||
if (!stat.value) return undefined;
|
||||
fn.argnames.forEach(function(sym, i) {
|
||||
var value = args[i];
|
||||
sym.definition().references.forEach(function(node) {
|
||||
@@ -3049,7 +3095,11 @@ merge(Compressor.prototype, {
|
||||
cached.push(node);
|
||||
});
|
||||
});
|
||||
return stat.value ? stat.value._eval(compressor, cached, depth) : undefined;
|
||||
fn.evaluating = true;
|
||||
var val = stat.value._eval(compressor, cached, depth);
|
||||
delete fn.evaluating;
|
||||
if (val === stat.value) return this;
|
||||
return val;
|
||||
} else if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
||||
var key = exp.property;
|
||||
if (key instanceof AST_Node) {
|
||||
@@ -3691,10 +3741,20 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
if (value) {
|
||||
props.push(value);
|
||||
return maintain_this_binding(compressor, parent, node, make_sequence(node, props.map(function(prop) {
|
||||
return prop.transform(tt);
|
||||
})));
|
||||
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
|
||||
value = value.drop_side_effect_free(compressor);
|
||||
}
|
||||
if (value) props.push(value);
|
||||
switch (props.length) {
|
||||
case 0:
|
||||
return MAP.skip;
|
||||
case 1:
|
||||
return maintain_this_binding(compressor, parent, node, props[0].transform(tt));
|
||||
default:
|
||||
return make_sequence(node, props.map(function(prop) {
|
||||
return prop.transform(tt);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3838,15 +3898,33 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
// certain combination of unused name + side effect leads to:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/44
|
||||
// https://github.com/mishoo/UglifyJS2/issues/1830
|
||||
// https://github.com/mishoo/UglifyJS2/issues/1838
|
||||
// https://github.com/mishoo/UglifyJS2/issues/3371
|
||||
// that's an invalid AST.
|
||||
// We fix it at this stage by moving the `var` outside the `for`.
|
||||
if (node instanceof AST_For) {
|
||||
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
||||
// Certain combination of unused name + side effect leads to invalid AST:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/1830
|
||||
// We fix it at this stage by moving the label inwards, back to the `for`.
|
||||
descend(node, this);
|
||||
if (node.body instanceof AST_BlockStatement) {
|
||||
var block = node.body;
|
||||
node.body = block.body.pop();
|
||||
block.body.push(node);
|
||||
return in_list ? MAP.splice(block.body) : block;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
var save_scope = scope;
|
||||
scope = node;
|
||||
descend(node, this);
|
||||
scope = save_scope;
|
||||
return node;
|
||||
}
|
||||
}, function(node, in_list) {
|
||||
if (node instanceof AST_For) {
|
||||
// Certain combination of unused name + side effect leads to invalid AST:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/44
|
||||
// https://github.com/mishoo/UglifyJS2/issues/1838
|
||||
// https://github.com/mishoo/UglifyJS2/issues/3371
|
||||
// We fix it at this stage by moving the `var` outside the `for`.
|
||||
var block;
|
||||
if (node.init instanceof AST_BlockStatement) {
|
||||
block = node.init;
|
||||
@@ -3867,36 +3945,23 @@ merge(Compressor.prototype, {
|
||||
node.init = null;
|
||||
}
|
||||
return !block ? node : in_list ? MAP.splice(block.body) : block;
|
||||
}
|
||||
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
||||
descend(node, this);
|
||||
if (node.body instanceof AST_BlockStatement) {
|
||||
var block = node.body;
|
||||
node.body = block.body.pop();
|
||||
block.body.push(node);
|
||||
return in_list ? MAP.splice(block.body) : block;
|
||||
} else if (node instanceof AST_ForIn) {
|
||||
if (!drop_vars || !compressor.option("loops")) return;
|
||||
if (!(node.init instanceof AST_Definitions)) return;
|
||||
var sym = node.init.definitions[0].name;
|
||||
if (sym.definition().id in in_use_ids) return;
|
||||
if (!is_empty(node.body)) return;
|
||||
log(sym, "Dropping unused loop variable {name} [{file}:{line},{col}]", template(sym));
|
||||
var value = node.object.drop_side_effect_free(compressor);
|
||||
if (value) {
|
||||
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", template(sym));
|
||||
return make_node(AST_SimpleStatement, node, {
|
||||
body: value
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
var save_scope = scope;
|
||||
scope = node;
|
||||
descend(node, this);
|
||||
scope = save_scope;
|
||||
return node;
|
||||
}
|
||||
|
||||
function log(sym, text, props) {
|
||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
||||
}
|
||||
|
||||
function template(sym) {
|
||||
return {
|
||||
name : sym.name,
|
||||
file : sym.start.file,
|
||||
line : sym.start.line,
|
||||
col : sym.start.col
|
||||
};
|
||||
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
||||
} else if (node instanceof AST_Sequence) {
|
||||
if (node.expressions.length == 1) return node.expressions[0];
|
||||
}
|
||||
});
|
||||
tt.push(compressor.parent());
|
||||
@@ -3905,6 +3970,19 @@ merge(Compressor.prototype, {
|
||||
fn.name = null;
|
||||
});
|
||||
|
||||
function log(sym, text, props) {
|
||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
||||
}
|
||||
|
||||
function template(sym) {
|
||||
return {
|
||||
name: sym.name,
|
||||
file: sym.start.file,
|
||||
line: sym.start.line,
|
||||
col : sym.start.col
|
||||
};
|
||||
}
|
||||
|
||||
function verify_safe_usage(def, read, modified) {
|
||||
if (def.id in in_use_ids) return;
|
||||
if (read && modified) {
|
||||
@@ -4792,10 +4870,12 @@ merge(Compressor.prototype, {
|
||||
for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
|
||||
branch = self.body[i];
|
||||
if (branch instanceof AST_Default) {
|
||||
if (!default_branch) {
|
||||
default_branch = branch;
|
||||
var prev = body[body.length - 1];
|
||||
if (default_branch || is_break(branch.body[0], compressor) && (!prev || aborts(prev))) {
|
||||
eliminate_branch(branch, prev);
|
||||
continue;
|
||||
} else {
|
||||
eliminate_branch(branch, body[body.length - 1]);
|
||||
default_branch = branch;
|
||||
}
|
||||
} else if (!(value instanceof AST_Node)) {
|
||||
var exp = branch.expression.evaluate(compressor);
|
||||
@@ -4824,16 +4904,20 @@ merge(Compressor.prototype, {
|
||||
body.push(branch);
|
||||
}
|
||||
while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
|
||||
if (body.length > 0) {
|
||||
body[0].body = decl.concat(body[0].body);
|
||||
}
|
||||
self.body = body;
|
||||
while (branch = body[body.length - 1]) {
|
||||
var stat = branch.body[branch.body.length - 1];
|
||||
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat) === self)
|
||||
branch.body.pop();
|
||||
if (branch.body.length || branch instanceof AST_Case
|
||||
&& (default_branch || branch.expression.has_side_effects(compressor))) break;
|
||||
if (is_break(stat, compressor)) branch.body.pop();
|
||||
if (branch === default_branch) {
|
||||
if (!is_body_empty(branch)) break;
|
||||
} else if (branch.expression.has_side_effects(compressor)) {
|
||||
break;
|
||||
} else if (default_branch) {
|
||||
if (!is_body_empty(default_branch)) break;
|
||||
if (body[body.length - 2] !== default_branch) break;
|
||||
default_branch.body = default_branch.body.concat(branch.body);
|
||||
branch.body = [];
|
||||
} else if (!is_body_empty(branch)) break;
|
||||
eliminate_branch(branch);
|
||||
if (body.pop() === default_branch) default_branch = null;
|
||||
}
|
||||
if (body.length == 0) {
|
||||
@@ -4843,14 +4927,15 @@ merge(Compressor.prototype, {
|
||||
}))
|
||||
}).optimize(compressor);
|
||||
}
|
||||
body[0].body = decl.concat(body[0].body);
|
||||
self.body = body;
|
||||
if (body.length == 1 && (body[0] === exact_match || body[0] === default_branch)) {
|
||||
var has_break = false;
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (has_break
|
||||
|| node instanceof AST_Lambda
|
||||
|| node instanceof AST_SimpleStatement) return true;
|
||||
if (node instanceof AST_Break && tw.loopcontrol_target(node) === self)
|
||||
has_break = true;
|
||||
if (is_break(node, tw)) has_break = true;
|
||||
});
|
||||
self.walk(tw);
|
||||
if (!has_break) {
|
||||
@@ -4869,6 +4954,20 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return self;
|
||||
|
||||
function is_break(node, tw) {
|
||||
return node instanceof AST_Break && tw.loopcontrol_target(node) === self;
|
||||
}
|
||||
|
||||
function is_body_empty(branch) {
|
||||
return all(branch.body, function(stat) {
|
||||
return is_empty(stat)
|
||||
|| stat instanceof AST_Defun
|
||||
|| stat instanceof AST_Var && all(stat.definitions, function(var_def) {
|
||||
return !var_def.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function eliminate_branch(branch, prev) {
|
||||
if (prev && !aborts(prev)) {
|
||||
prev.body = prev.body.concat(branch.body);
|
||||
@@ -5249,15 +5348,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var stat = is_func && fn.body[0];
|
||||
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||
if (can_inline && stat instanceof AST_Return) {
|
||||
if (exp === fn && can_inline && stat instanceof AST_Return) {
|
||||
var value = stat.value;
|
||||
if (!value || value.is_constant_expression()) {
|
||||
if (value) {
|
||||
value = value.clone(true);
|
||||
} else {
|
||||
value = make_node(AST_Undefined, self);
|
||||
}
|
||||
var args = self.args.concat(value);
|
||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
@@ -5277,6 +5371,7 @@ merge(Compressor.prototype, {
|
||||
&& !fn.contains_this()
|
||||
&& can_inject_symbols()) {
|
||||
fn._squeezed = true;
|
||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||
return make_sequence(self, flatten_fn()).optimize(compressor);
|
||||
}
|
||||
if (compressor.option("side_effects")
|
||||
@@ -5302,12 +5397,7 @@ merge(Compressor.prototype, {
|
||||
&& is_iife_call(self)) {
|
||||
return self.negate(compressor, true);
|
||||
}
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
return try_evaluate(compressor, self);
|
||||
|
||||
function return_value(stat) {
|
||||
if (!stat) return make_node(AST_Undefined, self);
|
||||
@@ -5494,6 +5584,11 @@ merge(Compressor.prototype, {
|
||||
definitions: decls
|
||||
}));
|
||||
[].splice.apply(scope.body, args);
|
||||
fn.enclosed.forEach(function(def) {
|
||||
if (scope.var_names()[def.name]) return;
|
||||
scope.enclosed.push(def);
|
||||
scope.var_names()[def.name] = true;
|
||||
});
|
||||
return expressions;
|
||||
}
|
||||
});
|
||||
@@ -5638,15 +5733,8 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
// avoids infinite recursion of numerals
|
||||
if (self.operator != "-"
|
||||
|| !(e instanceof AST_Number || e instanceof AST_Infinity)) {
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
return self.operator == "-" && (e instanceof AST_Number || e instanceof AST_Infinity)
|
||||
? self : try_evaluate(compressor, self);
|
||||
});
|
||||
|
||||
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
|
||||
@@ -6110,38 +6198,12 @@ merge(Compressor.prototype, {
|
||||
&& self.left.operator != "%"
|
||||
&& PRECEDENCE[self.left.operator] == PRECEDENCE[self.operator]
|
||||
&& self.left.is_number(compressor)) {
|
||||
if (self.left.left instanceof AST_Constant
|
||||
&& (self.operator != "+"
|
||||
|| self.left.left.is_boolean(compressor)
|
||||
|| self.left.left.is_number(compressor))) {
|
||||
self = make_node(AST_Binary, self, {
|
||||
operator: self.left.operator,
|
||||
left: make_node(AST_Binary, self.left, {
|
||||
operator: self.operator,
|
||||
left: self.left.left,
|
||||
right: self.right,
|
||||
start: self.left.left.start,
|
||||
end: self.right.end
|
||||
}),
|
||||
right: self.left.right
|
||||
});
|
||||
if (self.left.left instanceof AST_Constant) {
|
||||
var lhs = make_binary(self.left, self.operator, self.left.left, self.right, self.left.left.start, self.right.end);
|
||||
self = make_binary(self, self.left.operator, lhs, self.left.right);
|
||||
} else if (self.left.right instanceof AST_Constant) {
|
||||
var op = align(self.left.operator, self.operator);
|
||||
if (op != "+"
|
||||
|| self.left.right.is_boolean(compressor)
|
||||
|| self.left.right.is_number(compressor)) {
|
||||
self = make_node(AST_Binary, self, {
|
||||
operator: self.left.operator,
|
||||
left: self.left.left,
|
||||
right: make_node(AST_Binary, self.left, {
|
||||
operator: op,
|
||||
left: self.left.right,
|
||||
right: self.right,
|
||||
start: self.left.right.start,
|
||||
end: self.right.end
|
||||
})
|
||||
});
|
||||
}
|
||||
var rhs = make_binary(self.left, align(self.left.operator, self.operator), self.left.right, self.right, self.left.right.start, self.right.end);
|
||||
self = make_binary(self, self.left.operator, self.left.left, rhs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -6210,12 +6272,7 @@ merge(Compressor.prototype, {
|
||||
self.right = self.right.right;
|
||||
return self.transform(compressor);
|
||||
}
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
return try_evaluate(compressor, self);
|
||||
|
||||
function align(ref, op) {
|
||||
switch (ref) {
|
||||
@@ -6228,6 +6285,30 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function make_binary(orig, op, left, right, start, end) {
|
||||
if (op == "+") {
|
||||
if (!left.is_boolean(compressor) && !left.is_number(compressor)) {
|
||||
left = make_node(AST_UnaryPrefix, left, {
|
||||
operator: "+",
|
||||
expression: left
|
||||
});
|
||||
}
|
||||
if (!right.is_boolean(compressor) && !right.is_number(compressor)) {
|
||||
right = make_node(AST_UnaryPrefix, right, {
|
||||
operator: "+",
|
||||
expression: right
|
||||
});
|
||||
}
|
||||
}
|
||||
return make_node(AST_Binary, orig, {
|
||||
operator: op,
|
||||
left: left,
|
||||
right: right,
|
||||
start: start,
|
||||
end: end
|
||||
});
|
||||
}
|
||||
|
||||
function fuzzy_eval(node) {
|
||||
if (node.truthy) return true;
|
||||
if (node.falsy) return false;
|
||||
@@ -6307,6 +6388,7 @@ merge(Compressor.prototype, {
|
||||
} while (scope = scope.parent_scope);
|
||||
}
|
||||
}
|
||||
if (single_use) fixed.parent_scope = self.scope;
|
||||
}
|
||||
if (single_use && fixed) {
|
||||
def.single_use = false;
|
||||
@@ -6384,11 +6466,11 @@ merge(Compressor.prototype, {
|
||||
};
|
||||
}
|
||||
var name_length = def.name.length;
|
||||
var overhead = 0;
|
||||
if (compressor.option("unused") && !compressor.exposed(def)) {
|
||||
overhead = (name_length + 2 + value_length) / (def.references.length - def.assignments);
|
||||
name_length += (name_length + 2 + value_length) / (def.references.length - def.assignments);
|
||||
}
|
||||
def.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||
var delta = value_length - Math.floor(name_length);
|
||||
def.should_replace = delta < compressor.eval_threshold ? fn : false;
|
||||
} else {
|
||||
def.should_replace = false;
|
||||
}
|
||||
@@ -6512,23 +6594,30 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
} else if (self.left instanceof AST_SymbolRef) {
|
||||
if (self.left.is_immutable()) return strip_assignment();
|
||||
var def = self.left.definition();
|
||||
if (def.scope === compressor.find_parent(AST_Lambda)) {
|
||||
if (self.left.is_immutable()) return strip_assignment();
|
||||
var level = 0, node, parent = self;
|
||||
do {
|
||||
node = parent;
|
||||
parent = compressor.parent(level++);
|
||||
if (parent instanceof AST_Exit) {
|
||||
if (in_try(level, parent)) break;
|
||||
if (is_reachable(def.scope, [ def ])) break;
|
||||
def.fixed = false;
|
||||
return strip_assignment();
|
||||
}
|
||||
} while (parent instanceof AST_Binary && parent.right === node
|
||||
|| parent instanceof AST_Sequence && parent.tail_node() === node
|
||||
|| parent instanceof AST_UnaryPrefix);
|
||||
}
|
||||
var scope = def.scope.resolve();
|
||||
var local = scope === compressor.find_parent(AST_Lambda);
|
||||
var level = 0, node, parent = self;
|
||||
do {
|
||||
node = parent;
|
||||
parent = compressor.parent(level++);
|
||||
if (parent instanceof AST_Assign) {
|
||||
if (!(parent.left instanceof AST_SymbolRef)) continue;
|
||||
if (parent.left.definition() !== def) continue;
|
||||
if (in_try(level, parent)) break;
|
||||
def.fixed = false;
|
||||
return strip_assignment();
|
||||
} else if (parent instanceof AST_Exit) {
|
||||
if (!local) break;
|
||||
if (in_try(level, parent)) break;
|
||||
if (is_reachable(scope, [ def ])) break;
|
||||
def.fixed = false;
|
||||
return strip_assignment();
|
||||
}
|
||||
} while (parent instanceof AST_Binary && parent.right === node
|
||||
|| parent instanceof AST_Sequence && parent.tail_node() === node
|
||||
|| parent instanceof AST_UnaryPrefix);
|
||||
}
|
||||
}
|
||||
self = self.lift_sequences(compressor);
|
||||
@@ -6568,9 +6657,9 @@ merge(Compressor.prototype, {
|
||||
self.right = make_node(AST_Null, right);
|
||||
var may_throw = node.may_throw(compressor);
|
||||
self.right = right;
|
||||
var scope = self.left.definition().scope;
|
||||
var parent;
|
||||
while ((parent = compressor.parent(level++)) !== scope) {
|
||||
while (parent = compressor.parent(level++)) {
|
||||
if (parent === scope) return false;
|
||||
if (parent instanceof AST_Try) {
|
||||
if (parent.bfinally) return true;
|
||||
if (may_throw && parent.bcatch) return true;
|
||||
@@ -6637,7 +6726,7 @@ merge(Compressor.prototype, {
|
||||
&& alt_tail instanceof AST_Assign
|
||||
&& seq_tail.operator == alt_tail.operator
|
||||
&& seq_tail.left.equivalent_to(alt_tail.left)
|
||||
&& (is_eq && !seq_tail.left.has_side_effects(compressor)
|
||||
&& (is_eq && seq_tail.left instanceof AST_SymbolRef
|
||||
|| !condition.has_side_effects(compressor)
|
||||
&& can_shift_lhs_of_tail(consequent)
|
||||
&& can_shift_lhs_of_tail(alternative))) {
|
||||
@@ -6806,16 +6895,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function can_shift_lhs_of_tail(node) {
|
||||
if (node === node.tail_node()) return true;
|
||||
var exprs = node.expressions;
|
||||
for (var i = exprs.length - 1; --i >= 0;) {
|
||||
var expr = exprs[i];
|
||||
if (!(expr instanceof AST_Assign) && expr.has_side_effects(compressor)
|
||||
|| expr.operator != "="
|
||||
|| expr.left.has_side_effects(compressor)
|
||||
|| expr.right.has_side_effects(compressor)) return false;
|
||||
}
|
||||
return true;
|
||||
return node === node.tail_node() || all(node.expressions.slice(0, -1), function(expr) {
|
||||
return !expr.has_side_effects(compressor);
|
||||
});
|
||||
}
|
||||
|
||||
function pop_lhs(node) {
|
||||
@@ -6982,12 +7064,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
return try_evaluate(compressor, self);
|
||||
|
||||
function find_lambda() {
|
||||
var i = 0, p;
|
||||
@@ -7088,17 +7165,11 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var sub = self.flatten_object(self.property, compressor);
|
||||
if (sub) return sub.optimize(compressor);
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
return self;
|
||||
return try_evaluate(compressor, self);
|
||||
});
|
||||
|
||||
OPT(AST_Object, function(self, compressor) {
|
||||
if (!compressor.option("objects") || compressor.has_directive("use strict")) return self;
|
||||
var props = self.properties;
|
||||
var keys = new Dictionary();
|
||||
var values = [];
|
||||
self.properties.forEach(function(prop) {
|
||||
|
||||
@@ -252,7 +252,7 @@ function minify(files, options) {
|
||||
properties: 1e-3 * (timings.output - timings.properties),
|
||||
output: 1e-3 * (timings.end - timings.output),
|
||||
total: 1e-3 * (timings.end - timings.start)
|
||||
}
|
||||
};
|
||||
}
|
||||
if (warnings.length) {
|
||||
result.warnings = warnings;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.6.7",
|
||||
"version": "3.7.0",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -1458,7 +1458,7 @@ collapse_vars_constants: {
|
||||
function f3(x) {
|
||||
var b = x.prop;
|
||||
sideeffect1();
|
||||
return b + (function() { return -9; })();
|
||||
return b + -9;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5748,7 +5748,7 @@ issue_3215_1: {
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log("number");
|
||||
console.log(typeof 42);
|
||||
}
|
||||
expect_stdout: "number"
|
||||
}
|
||||
@@ -6238,7 +6238,7 @@ issue_3439_2: {
|
||||
expect_stdout: "number"
|
||||
}
|
||||
|
||||
cond_sequence_return: {
|
||||
cond_sequence_return_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
@@ -6259,6 +6259,27 @@ cond_sequence_return: {
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
cond_sequence_return_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(n) {
|
||||
var c = 0;
|
||||
for (var k in [0, 1])
|
||||
if (c += 1, k == n) return c;
|
||||
}(1));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(n) {
|
||||
var c = 0;
|
||||
for (var k in [0, 1])
|
||||
if (c += 1, k == n) return c;
|
||||
}(1));
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_3520: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -6387,3 +6408,144 @@ issue_3562: {
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
dot_throw_assign_sequence: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
var b;
|
||||
b[0] = (a = "PASS", 0);
|
||||
a = 1 + a;
|
||||
} catch (c) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
var b;
|
||||
b[0] = (a = "PASS", 0);
|
||||
a = 1 + a;
|
||||
} catch (c) {
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
call_assign_order: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a, b = 1, c = 0, log = console.log;
|
||||
(function() {
|
||||
a = b = "PASS";
|
||||
})((b = "FAIL", c++));
|
||||
log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a, b = 1, c = 0, log = console.log;
|
||||
(function() {
|
||||
a = b = "PASS";
|
||||
})((b = "FAIL", c++));
|
||||
log(a, b);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
issue_3573: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function(b) {
|
||||
while (--b) {
|
||||
b = NaN;
|
||||
switch (0 / this < 0) {
|
||||
case c++, false:
|
||||
case c++, NaN:
|
||||
}
|
||||
}
|
||||
})(3);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function(b) {
|
||||
while (--b) {
|
||||
b = NaN;
|
||||
switch (0 / this < 0) {
|
||||
case c++, false:
|
||||
case c++, NaN:
|
||||
}
|
||||
}
|
||||
})(3);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3581_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS", b = "FAIL";
|
||||
try {
|
||||
b = "PASS";
|
||||
if (a) throw 0;
|
||||
b = 1 + b;
|
||||
a = "FAIL";
|
||||
} catch (e) {}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b = "FAIL";
|
||||
try {
|
||||
b = "PASS";
|
||||
if (a) throw 0;
|
||||
b = 1 + b;
|
||||
a = "FAIL";
|
||||
} catch (e) {}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
issue_3581_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = "PASS", b = "FAIL";
|
||||
try {
|
||||
b = "PASS";
|
||||
if (a) return;
|
||||
b = 1 + b;
|
||||
a = "FAIL";
|
||||
} finally {
|
||||
console.log(a, b);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a = "PASS", b = "FAIL";
|
||||
try {
|
||||
b = "PASS";
|
||||
if (a) return;
|
||||
b = 1 + b;
|
||||
a = "FAIL";
|
||||
} finally {
|
||||
console.log(a, b);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
@@ -1489,3 +1489,29 @@ angularjs_chain: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3576: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function(a) {
|
||||
(a = -1) ? (a && (a.a = 0)) : (a && (a.a = 0));
|
||||
a && a[c = "PASS"]++;
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function(a) {
|
||||
a = -1, a, a.a = 0;
|
||||
a, a[c = "PASS"]++;
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -892,9 +892,7 @@ issue_2860_1: {
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1 ^ a;
|
||||
}());
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
@@ -1064,3 +1062,68 @@ issue_3552: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
unreachable_assign: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
console.log(A = "P" + (A = "A" + (B = "S" + (A = B = "S"))), A, B);
|
||||
}
|
||||
expect: {
|
||||
console.log(A = "P" + "A" + (B = "S" + "S"), A, B);
|
||||
}
|
||||
expect_stdout: "PASS PASS SS"
|
||||
}
|
||||
|
||||
catch_return_assign: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
return e = "PASS";
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
return "PASS";
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3578: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL", b, c;
|
||||
try {
|
||||
b = c.p = b = 0;
|
||||
} catch (e) {
|
||||
b += 42;
|
||||
b && (a = "PASS");
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL", b, c;
|
||||
try {
|
||||
b = c.p = b = 0;
|
||||
} catch (e) {
|
||||
b += 42;
|
||||
b && (a = "PASS");
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1019,14 +1019,21 @@ delete_assign_1: {
|
||||
console.log(delete (a = 0 / 0));
|
||||
}
|
||||
expect: {
|
||||
console.log((void 0, !0));
|
||||
console.log((void 0, !0));
|
||||
console.log((1 / 0, !0));
|
||||
console.log((1 / 0, !0));
|
||||
console.log((NaN, !0));
|
||||
console.log((NaN, !0));
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
delete_assign_2: {
|
||||
@@ -1047,14 +1054,21 @@ delete_assign_2: {
|
||||
console.log(delete (a = 0 / 0));
|
||||
}
|
||||
expect: {
|
||||
console.log((void 0, !0));
|
||||
console.log((void 0, !0));
|
||||
console.log((Infinity, !0));
|
||||
console.log((1 / 0, !0));
|
||||
console.log((NaN, !0));
|
||||
console.log((NaN, !0));
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
console.log(!0);
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
drop_var: {
|
||||
@@ -1635,7 +1649,7 @@ double_assign_2: {
|
||||
}
|
||||
expect: {
|
||||
for (var i = 0; i < 2; i++)
|
||||
void 0, a = {}, console.log(a);
|
||||
a = {}, console.log(a);
|
||||
var a;
|
||||
}
|
||||
}
|
||||
@@ -1716,7 +1730,7 @@ issue_2768: {
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
var c = (d = a, 0, void (d && (a = "PASS")));
|
||||
var c = (d = a, void (d && (a = "PASS")));
|
||||
var d;
|
||||
console.log(a, typeof c);
|
||||
}
|
||||
|
||||
@@ -1876,3 +1876,184 @@ issue_3558: {
|
||||
}
|
||||
expect_stdout: "1 0"
|
||||
}
|
||||
|
||||
issue_3568: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
function f(b) {
|
||||
return b && b.p;
|
||||
}
|
||||
console.log(f(++a + f()));
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
function f(b) {
|
||||
return b && b.p;
|
||||
}
|
||||
console.log(NaN);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
conditional_function: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
return a && "undefined" != typeof A ? A : 42;
|
||||
}
|
||||
console.log(f(0), f(1));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
return a && "undefined" != typeof A ? A : 42;
|
||||
}
|
||||
console.log(42, f(1));
|
||||
}
|
||||
expect_stdout: "42 42"
|
||||
}
|
||||
|
||||
best_of_evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function d(x, y) {
|
||||
return x / y;
|
||||
}
|
||||
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
|
||||
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
|
||||
}
|
||||
expect: {
|
||||
function d(x, y) {
|
||||
return x / y;
|
||||
}
|
||||
console.log(0, 1 / 64, 4 / 7, 1);
|
||||
console.log(0, .015625, d(4, 7), 1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0.015625 0.5714285714285714 1",
|
||||
"0 0.015625 0.5714285714285714 1",
|
||||
]
|
||||
}
|
||||
|
||||
eager_evaluate: {
|
||||
options = {
|
||||
evaluate: "eager",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function d(x, y) {
|
||||
return x / y;
|
||||
}
|
||||
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
|
||||
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
|
||||
}
|
||||
expect: {
|
||||
console.log(0, .015625, .5714285714285714, 1);
|
||||
console.log(0, .015625, .5714285714285714, 1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0.015625 0.5714285714285714 1",
|
||||
"0 0.015625 0.5714285714285714 1",
|
||||
]
|
||||
}
|
||||
|
||||
threshold_evaluate_default: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
|
||||
}
|
||||
expect: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log("111", 6, b(b(b("ABCDEFGHIJK"))));
|
||||
}
|
||||
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
|
||||
}
|
||||
|
||||
threshold_evaluate_30: {
|
||||
options = {
|
||||
evaluate: 30,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
|
||||
}
|
||||
expect: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log("111", 6, b(b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK")));
|
||||
}
|
||||
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
|
||||
}
|
||||
|
||||
threshold_evaluate_100: {
|
||||
options = {
|
||||
evaluate: 100,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
|
||||
}
|
||||
expect: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log("111", 6, b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"));
|
||||
}
|
||||
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
|
||||
}
|
||||
|
||||
threshold_evaluate_999: {
|
||||
options = {
|
||||
evaluate: 999,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function b(x) {
|
||||
return x + x + x;
|
||||
}
|
||||
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
|
||||
}
|
||||
expect: {
|
||||
console.log("111", 6, "ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK");
|
||||
}
|
||||
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
|
||||
}
|
||||
|
||||
@@ -2265,7 +2265,8 @@ issue_3054: {
|
||||
return { a: !0 };
|
||||
}
|
||||
console.log(function(b) {
|
||||
return { a: !(b = !1) };
|
||||
b = !1;
|
||||
return f();
|
||||
}().a, f.call().a);
|
||||
}
|
||||
expect_stdout: "true true"
|
||||
@@ -2345,7 +2346,7 @@ issue_3274: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
for (var c; void 0, (c = 1..p) != c;)
|
||||
for (var c; (c = 1..p) != c;)
|
||||
console.log("FAIL");
|
||||
console.log("PASS");
|
||||
})();
|
||||
@@ -2415,7 +2416,7 @@ issue_3297_2: {
|
||||
doProcessOne({
|
||||
param1: param1,
|
||||
param2: param2,
|
||||
}, function () {
|
||||
}, function() {
|
||||
processBulk(bulk);
|
||||
});
|
||||
};
|
||||
@@ -2496,7 +2497,7 @@ issue_3297_3: {
|
||||
doProcessOne({
|
||||
param1: param1,
|
||||
param2: param2,
|
||||
}, function () {
|
||||
}, function() {
|
||||
processBulk(bulk);
|
||||
});
|
||||
};
|
||||
@@ -2513,18 +2514,21 @@ issue_3297_3: {
|
||||
}).processBulk([1, 2, 3]);
|
||||
}
|
||||
expect: {
|
||||
function function1(u) {
|
||||
function function1(c) {
|
||||
return {
|
||||
processBulk: function n(r) {
|
||||
var o, t = u();
|
||||
r && 0 < r.length && (o = {
|
||||
param1: r.shift(),
|
||||
processBulk: function n(o) {
|
||||
var r, t, u = c();
|
||||
o && 0 < o.length && (r = {
|
||||
param1: o.shift(),
|
||||
param2: {
|
||||
subparam1: t
|
||||
subparam1: u
|
||||
}
|
||||
},
|
||||
console.log(JSON.stringify(o)),
|
||||
n(r));
|
||||
t = function() {
|
||||
n(o);
|
||||
},
|
||||
console.log(JSON.stringify(r)),
|
||||
t());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -3096,23 +3100,20 @@ issue_3400_1: {
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
void console.log(function() {
|
||||
function g() {
|
||||
function h(u) {
|
||||
var o = {
|
||||
p: u
|
||||
};
|
||||
return console.log(o[g]), o;
|
||||
}
|
||||
function e() {
|
||||
return [ 42 ].map(function(v) {
|
||||
return h(v);
|
||||
});
|
||||
}
|
||||
return e();
|
||||
void console.log(function g() {
|
||||
function h(u) {
|
||||
var o = {
|
||||
p: u
|
||||
};
|
||||
return console.log(o[g]), o;
|
||||
}
|
||||
return g;
|
||||
}()()[0].p);
|
||||
function e() {
|
||||
return [ 42 ].map(function(v) {
|
||||
return h(v);
|
||||
});
|
||||
}
|
||||
return e();
|
||||
}()[0].p);
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
@@ -3153,12 +3154,10 @@ issue_3400_2: {
|
||||
expect: {
|
||||
void console.log(function g() {
|
||||
return [ 42 ].map(function(v) {
|
||||
return function(u) {
|
||||
var o = {
|
||||
p: u
|
||||
};
|
||||
return console.log(o[g]), o;
|
||||
}(v);
|
||||
return o = {
|
||||
p: v
|
||||
}, console.log(o[g]), o;
|
||||
var o;
|
||||
});
|
||||
}()[0].p);
|
||||
}
|
||||
@@ -3400,3 +3399,172 @@ issue_3562: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
hoisted_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console.log("PASS");
|
||||
}
|
||||
function g() {
|
||||
for (var console in [ 0 ])
|
||||
h();
|
||||
}
|
||||
function h() {
|
||||
f();
|
||||
}
|
||||
g();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
console.log("PASS");
|
||||
}
|
||||
(function() {
|
||||
for (var console in [ 0 ])
|
||||
void f();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
hoisted_single_use: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
for (var r in a) g(r);
|
||||
}
|
||||
function g(a) {
|
||||
console.log(a);
|
||||
}
|
||||
function h(a) {
|
||||
var g = a.bar;
|
||||
g();
|
||||
g();
|
||||
i(a);
|
||||
}
|
||||
function i(b) {
|
||||
f(b);
|
||||
}
|
||||
h({
|
||||
bar: function() {
|
||||
console.log("foo");
|
||||
}
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
for (var r in a) g(r);
|
||||
}
|
||||
function g(a) {
|
||||
console.log(a);
|
||||
}
|
||||
(function(a) {
|
||||
var g = a.bar;
|
||||
g();
|
||||
g();
|
||||
(function(b) {
|
||||
f(b);
|
||||
})(a);
|
||||
})({
|
||||
bar: function() {
|
||||
console.log("foo");
|
||||
}
|
||||
});
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
}
|
||||
|
||||
pr_3592_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: false,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function problem(w) {
|
||||
return g.indexOf(w);
|
||||
}
|
||||
function unused(x) {
|
||||
return problem(x);
|
||||
}
|
||||
function B(problem) {
|
||||
return g[problem];
|
||||
}
|
||||
function A(y) {
|
||||
return problem(y);
|
||||
}
|
||||
function main(z) {
|
||||
return B(A(z));
|
||||
}
|
||||
var g = [ "PASS" ];
|
||||
console.log(main("PASS"));
|
||||
}
|
||||
expect: {
|
||||
function problem(w) {
|
||||
return g.indexOf(w);
|
||||
}
|
||||
function B(problem) {
|
||||
return g[problem];
|
||||
}
|
||||
var g = [ "PASS" ];
|
||||
console.log((z = "PASS", B((y = z, problem(y)))));
|
||||
var z, y;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
pr_3592_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function problem(w) {
|
||||
return g.indexOf(w);
|
||||
}
|
||||
function unused(x) {
|
||||
return problem(x);
|
||||
}
|
||||
function B(problem) {
|
||||
return g[problem];
|
||||
}
|
||||
function A(y) {
|
||||
return problem(y);
|
||||
}
|
||||
function main(z) {
|
||||
return B(A(z));
|
||||
}
|
||||
var g = [ "PASS" ];
|
||||
console.log(main("PASS"));
|
||||
}
|
||||
expect: {
|
||||
function problem(w) {
|
||||
return g.indexOf(w);
|
||||
}
|
||||
var g = [ "PASS" ];
|
||||
console.log((z = "PASS", function(problem) {
|
||||
return g[problem];
|
||||
}((y = z, problem(y)))));
|
||||
var z, y;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -52,3 +52,30 @@ chained_evaluation_2: {
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
chained_evaluation_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: 10,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = "long piece of string";
|
||||
(function() {
|
||||
var b = a, c;
|
||||
c = f(b);
|
||||
c.bar = b;
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function() {
|
||||
f("long piece of string").bar = "long piece of string";
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,3 +689,67 @@ step: {
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
empty_for_in: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var a in [ 1, 2, 3 ]) {
|
||||
var b = a + 1;
|
||||
}
|
||||
}
|
||||
expect: {}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unused variable b [test/compress/loops.js:2,16]",
|
||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
||||
]
|
||||
}
|
||||
|
||||
empty_for_in_used: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var a in [ 1, 2, 3 ]) {
|
||||
var b = a + 1;
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
for (var a in [ 1, 2, 3 ]);
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unused variable b [test/compress/loops.js:2,16]",
|
||||
]
|
||||
}
|
||||
|
||||
empty_for_in_side_effects: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var a in {
|
||||
foo: console.log("PASS")
|
||||
}) {
|
||||
var b = a + "bar";
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ issue_3547_3: {
|
||||
a + "21",
|
||||
a + "2" - 1,
|
||||
a - 1,
|
||||
a - "2" - 1,
|
||||
a - 3,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
@@ -904,7 +904,7 @@ issue_3547_4: {
|
||||
[
|
||||
"3" + a + 1,
|
||||
"3" + a - 1,
|
||||
"3" - a + 1,
|
||||
4 - a,
|
||||
2 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
@@ -917,3 +917,31 @@ issue_3547_4: {
|
||||
"number 0",
|
||||
]
|
||||
}
|
||||
|
||||
unsafe_math_rounding: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log(4 / -3 + 1 === 1 / -3);
|
||||
}
|
||||
expect: {
|
||||
console.log(false);
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
issue_3593: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log((0 === this) - 1 - "1");
|
||||
}
|
||||
expect: {
|
||||
console.log((0 === this) - 2);
|
||||
}
|
||||
expect_stdout: "-2"
|
||||
}
|
||||
|
||||
@@ -1427,13 +1427,13 @@ defun_inline_3: {
|
||||
|
||||
defun_call: {
|
||||
options = {
|
||||
inline: true,
|
||||
evaluate: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console.log(function f() {
|
||||
return g() + h(1) - h(g(), 2, 3);
|
||||
function g() {
|
||||
return 4;
|
||||
@@ -1441,21 +1441,17 @@ defun_call: {
|
||||
function h(a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return 4 + h(1) - h(4);
|
||||
function h(a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
defun_redefine: {
|
||||
options = {
|
||||
inline: true,
|
||||
evaluate: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -1480,7 +1476,7 @@ defun_redefine: {
|
||||
(function() {
|
||||
return 3;
|
||||
});
|
||||
return 3 + 2;
|
||||
return 5;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
@@ -1517,7 +1513,7 @@ func_inline: {
|
||||
|
||||
func_modified: {
|
||||
options = {
|
||||
inline: true,
|
||||
evaluate: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -1550,7 +1546,7 @@ func_modified: {
|
||||
(function() {
|
||||
return 4;
|
||||
});
|
||||
return 1 + 2 + 4;
|
||||
return 7;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
@@ -5516,9 +5512,7 @@ issue_2860_1: {
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1 ^ a;
|
||||
}());
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -261,13 +261,13 @@ drop_default_1: {
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
default:
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,14 +279,14 @@ drop_default_2: {
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case "bar": baz(); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,7 +298,7 @@ keep_default: {
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
default:
|
||||
something();
|
||||
break;
|
||||
@@ -306,7 +306,7 @@ keep_default: {
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
default:
|
||||
something();
|
||||
}
|
||||
@@ -347,25 +347,103 @@ issue_1663: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
drop_case: {
|
||||
drop_case_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case 'moo':
|
||||
case "bar": baz(); break;
|
||||
case "moo":
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
case "bar": baz();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop_case_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case "bar":
|
||||
bar();
|
||||
break;
|
||||
default:
|
||||
case "moo":
|
||||
moo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case "bar":
|
||||
bar();
|
||||
break;
|
||||
default:
|
||||
moo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop_case_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var c = "PASS";
|
||||
switch ({}.p) {
|
||||
default:
|
||||
case void 0:
|
||||
break;
|
||||
case c = "FAIL":
|
||||
}
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "PASS";
|
||||
switch ({}.p) {
|
||||
default:
|
||||
case void 0:
|
||||
break;
|
||||
case c = "FAIL":
|
||||
}
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
drop_case_4: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (0) {
|
||||
case [ a, typeof b ]:
|
||||
default:
|
||||
var a;
|
||||
}
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
switch (0) {
|
||||
case [ a, typeof b ]:
|
||||
var a;
|
||||
}
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
keep_case: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
@@ -373,14 +451,14 @@ keep_case: {
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case "bar": baz(); break;
|
||||
case moo:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case "bar": baz(); break;
|
||||
case moo:
|
||||
}
|
||||
}
|
||||
@@ -539,7 +617,7 @@ issue_1679: {
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_stdout: "99 8"
|
||||
}
|
||||
|
||||
issue_1680_1: {
|
||||
@@ -864,3 +942,89 @@ issue_1750: {
|
||||
}
|
||||
expect_stdout: "0 2"
|
||||
}
|
||||
|
||||
drop_switch_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
default:
|
||||
break;
|
||||
case "bar":
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
foo;
|
||||
}
|
||||
}
|
||||
|
||||
drop_switch_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
default:
|
||||
case "bar":
|
||||
baz();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
foo;
|
||||
baz();
|
||||
}
|
||||
}
|
||||
|
||||
drop_switch_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
default:
|
||||
return "PASS";
|
||||
case 1:
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
default:
|
||||
return "PASS";
|
||||
case 1:
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
drop_switch_4: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
switch (0) {
|
||||
default:
|
||||
case a:
|
||||
var b = a = "PASS";
|
||||
break;
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
0;
|
||||
var b = a = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -166,9 +166,7 @@ duplicate_lambda_arg_name: {
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function long_name(long_name) {
|
||||
return typeof long_name;
|
||||
}());
|
||||
console.log("undefined");
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ describe("bin/uglifyjs", function() {
|
||||
it("Should produce a functional build when using --self", function(done) {
|
||||
this.timeout(30000);
|
||||
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
|
||||
exec(command, function(err, stdout) {
|
||||
exec(command, {
|
||||
maxBuffer: 1048576
|
||||
}, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
eval(stdout);
|
||||
assert.strictEqual(typeof WrappedUglifyJS, "object");
|
||||
|
||||
@@ -10,7 +10,9 @@ describe("spidermonkey export/import sanity test", function() {
|
||||
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
|
||||
uglifyjs + " -p spidermonkey -cm";
|
||||
|
||||
exec(command, function(err, stdout) {
|
||||
exec(command, {
|
||||
maxBuffer: 1048576
|
||||
}, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
eval(stdout);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var child_process = require("child_process");
|
||||
var https = require("https");
|
||||
var url = require("url");
|
||||
|
||||
var period = 45 * 60 * 1000;
|
||||
var wait = 2 * 60 * 1000;
|
||||
if (process.argv.length > 2) {
|
||||
var token = process.argv[2];
|
||||
var branch = process.argv[3] || "v" + require("../../package.json").version;
|
||||
var repository = encodeURIComponent(process.argv[4] || "mishoo/UglifyJS2");
|
||||
var concurrency = process.argv[5] || 1;
|
||||
var platform = process.argv[6] || "latest";
|
||||
(function request() {
|
||||
setTimeout(request, (period + wait) / concurrency);
|
||||
var options = url.parse("https://api.travis-ci.org/repo/" + repository + "/requests");
|
||||
options.method = "POST";
|
||||
options.headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Travis-API-Version": 3,
|
||||
"Authorization": "token " + token
|
||||
};
|
||||
https.request(options, function(res) {
|
||||
console.log("HTTP", res.statusCode);
|
||||
console.log(JSON.stringify(res.headers, null, 2));
|
||||
console.log();
|
||||
res.setEncoding("utf8");
|
||||
res.on("data", console.log);
|
||||
}).on("error", console.error).end(JSON.stringify({
|
||||
request: {
|
||||
message: "ufuzz testing",
|
||||
branch: branch,
|
||||
config: {
|
||||
cache: false,
|
||||
env: "NODE=" + platform,
|
||||
script: "node test/ufuzz/job " + period
|
||||
}
|
||||
}
|
||||
}));
|
||||
})();
|
||||
} else {
|
||||
console.log("Usage: test/ufuzz/travis.js <token> [branch] [repository] [concurrency] [platform]");
|
||||
}
|
||||
Reference in New Issue
Block a user