Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25441d44f6 | ||
|
|
a025392a30 | ||
|
|
ad5f5ef2a3 | ||
|
|
40e669eacb | ||
|
|
ad3a331ca3 | ||
|
|
3c9e1693d5 | ||
|
|
8bc03dc6c4 | ||
|
|
2152f00de2 | ||
|
|
94aae05d45 | ||
|
|
0dbf2b1d3c | ||
|
|
59b23b8c13 | ||
|
|
5979b195fe | ||
|
|
a1cff23377 | ||
|
|
c82fc1ef71 | ||
|
|
740f93f5a9 | ||
|
|
d4caa97b88 | ||
|
|
c2ca7b7659 | ||
|
|
59edda6ca5 | ||
|
|
1668bc33c3 | ||
|
|
01f1e3fef8 | ||
|
|
27aa85f84b | ||
|
|
33c9c48318 | ||
|
|
63f16e4616 | ||
|
|
cb6dd34b98 | ||
|
|
27727e6926 | ||
|
|
a968ddc78c | ||
|
|
f70462aeb2 | ||
|
|
3aa92c76cc | ||
|
|
fc6a66836a | ||
|
|
31167da1a9 | ||
|
|
7db2ada880 | ||
|
|
e31bbe329a | ||
|
|
8946c87011 | ||
|
|
a9ef659bcb | ||
|
|
35c2149dbd | ||
|
|
89a35f9fcd | ||
|
|
1a4e99dc2d | ||
|
|
cb870f6fd6 | ||
|
|
a0c0c294c5 | ||
|
|
fbdb7eeda3 | ||
|
|
1bc0fccc8c | ||
|
|
20252c6483 | ||
|
|
e396912ea2 | ||
|
|
5ebfa78f56 | ||
|
|
950609f578 |
6
.github/workflows/ufuzz.yml
vendored
6
.github/workflows/ufuzz.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- node: latest
|
- node: '16'
|
||||||
os: macos-latest
|
os: macos-latest
|
||||||
- node: '8'
|
- node: '12'
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
- node: '8'
|
- node: '8'
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
- node: '8'
|
- node: '12'
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
- node: '8'
|
- node: '8'
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -118,6 +118,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
--keep-fargs Do not mangle/drop function arguments.
|
--keep-fargs Do not mangle/drop function arguments.
|
||||||
--keep-fnames Do not mangle/drop function names. Useful for
|
--keep-fnames Do not mangle/drop function names. Useful for
|
||||||
code relying on Function.prototype.name.
|
code relying on Function.prototype.name.
|
||||||
|
--module Process input as ES module (implies --toplevel)
|
||||||
--name-cache <file> File to hold mangled name mappings.
|
--name-cache <file> File to hold mangled name mappings.
|
||||||
--self Build UglifyJS as a library (implies --wrap UglifyJS)
|
--self Build UglifyJS as a library (implies --wrap UglifyJS)
|
||||||
--source-map [options] Enable source map/specify source map options:
|
--source-map [options] Enable source map/specify source map options:
|
||||||
@@ -146,7 +147,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
--warn Print warning messages.
|
--warn Print warning messages.
|
||||||
--webkit Support non-standard Safari/Webkit.
|
--webkit Support non-standard Safari/Webkit.
|
||||||
Equivalent to setting `webkit: true` in `minify()`
|
Equivalent to setting `webkit: true` in `minify()`
|
||||||
for `mangle` and `output` options.
|
for `compress`, `mangle` and `output` options.
|
||||||
By default UglifyJS will not try to be Safari-proof.
|
By default UglifyJS will not try to be Safari-proof.
|
||||||
--wrap <name> Embed everything in a big function, making the
|
--wrap <name> Embed everything in a big function, making the
|
||||||
“exports” and “global” variables available. You
|
“exports” and “global” variables available. You
|
||||||
@@ -517,6 +518,9 @@ if (result.error) throw result.error;
|
|||||||
- `mangle.properties` (default: `false`) — a subcategory of the mangle option.
|
- `mangle.properties` (default: `false`) — a subcategory of the mangle option.
|
||||||
Pass an object to specify custom [mangle property options](#mangle-properties-options).
|
Pass an object to specify custom [mangle property options](#mangle-properties-options).
|
||||||
|
|
||||||
|
- `module` (default: `false`) — set to `true` if you wish to process input as
|
||||||
|
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
|
||||||
|
|
||||||
- `nameCache` (default: `null`) — pass an empty object `{}` or a previously
|
- `nameCache` (default: `null`) — pass an empty object `{}` or a previously
|
||||||
used `nameCache` object if you wish to cache mangled variable and
|
used `nameCache` object if you wish to cache mangled variable and
|
||||||
property names across multiple invocations of `minify()`. Note: this is
|
property names across multiple invocations of `minify()`. Note: this is
|
||||||
@@ -728,6 +732,9 @@ to be `false` and all symbol names will be omitted.
|
|||||||
|
|
||||||
- `merge_vars` (default: `true`) — combine and reuse variables.
|
- `merge_vars` (default: `true`) — combine and reuse variables.
|
||||||
|
|
||||||
|
- `module` (default: `false`) — set to `true` if you wish to process input as
|
||||||
|
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
|
||||||
|
|
||||||
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
|
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
|
||||||
where the return value is discarded, to avoid the parens that the
|
where the return value is discarded, to avoid the parens that the
|
||||||
code generator would insert.
|
code generator would insert.
|
||||||
@@ -1331,10 +1338,8 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
||||||
```javascript
|
```javascript
|
||||||
var await;
|
var await;
|
||||||
async function f() {
|
class A {
|
||||||
class A {
|
static p = await;
|
||||||
static p = await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// SyntaxError: Unexpected reserved word
|
// SyntaxError: Unexpected reserved word
|
||||||
```
|
```
|
||||||
@@ -1373,3 +1378,46 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
// TypeError: const 'a' has already been declared
|
// TypeError: const 'a' has already been declared
|
||||||
```
|
```
|
||||||
UglifyJS may modify the input which in turn may suppress those errors.
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Later versions of Chrome and Node.js will give incorrect results with the
|
||||||
|
following:
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
class A {
|
||||||
|
static 42;
|
||||||
|
static get 42() {}
|
||||||
|
}
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL");
|
||||||
|
}
|
||||||
|
// Expected: "PASS"
|
||||||
|
// Actual: "FAIL"
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Some versions of Chrome and Node.js will give incorrect results with the
|
||||||
|
following:
|
||||||
|
```javascript
|
||||||
|
(async function(a) {
|
||||||
|
(function() {
|
||||||
|
var b = await => console.log("PASS");
|
||||||
|
b();
|
||||||
|
})();
|
||||||
|
})().catch(console.error);
|
||||||
|
// Expected: "PASS"
|
||||||
|
// Actual: SyntaxError: Unexpected reserved word
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Later versions of Chrome and Node.js will give incorrect results with the
|
||||||
|
following:
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
f();
|
||||||
|
function f() {
|
||||||
|
throw 42;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
console.log(typeof f);
|
||||||
|
// Expected: "function"
|
||||||
|
// Actual: "undefined"
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ function process_option(name, no_value) {
|
|||||||
" --ie Support non-standard Internet Explorer.",
|
" --ie Support non-standard Internet Explorer.",
|
||||||
" --keep-fargs Do not mangle/drop function arguments.",
|
" --keep-fargs Do not mangle/drop function arguments.",
|
||||||
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
|
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
|
||||||
|
" --module Process input as ES module (implies --toplevel)",
|
||||||
" --name-cache <file> File to hold mangled name mappings.",
|
" --name-cache <file> File to hold mangled name mappings.",
|
||||||
" --rename Force symbol expansion.",
|
" --rename Force symbol expansion.",
|
||||||
" --no-rename Disable symbol expansion.",
|
" --no-rename Disable symbol expansion.",
|
||||||
@@ -152,6 +153,7 @@ function process_option(name, no_value) {
|
|||||||
case "annotations":
|
case "annotations":
|
||||||
case "ie":
|
case "ie":
|
||||||
case "ie8":
|
case "ie8":
|
||||||
|
case "module":
|
||||||
case "timings":
|
case "timings":
|
||||||
case "toplevel":
|
case "toplevel":
|
||||||
case "v8":
|
case "v8":
|
||||||
|
|||||||
21
lib/ast.js
21
lib/ast.js
@@ -827,6 +827,9 @@ var AST_Class = DEFNODE("Class", "extends name properties", {
|
|||||||
extends: "[AST_Node?] the super class, or null if not specified",
|
extends: "[AST_Node?] the super class, or null if not specified",
|
||||||
properties: "[AST_ClassProperty*] array of class properties",
|
properties: "[AST_ClassProperty*] array of class properties",
|
||||||
},
|
},
|
||||||
|
resolve: function(def_class) {
|
||||||
|
return def_class ? this : this.parent_scope.resolve();
|
||||||
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
visitor.visit(node, function() {
|
visitor.visit(node, function() {
|
||||||
@@ -851,9 +854,6 @@ var AST_DefClass = DEFNODE("DefClass", null, {
|
|||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolDefClass] the name of this class",
|
name: "[AST_SymbolDefClass] the name of this class",
|
||||||
},
|
},
|
||||||
resolve: function(def_class) {
|
|
||||||
return def_class ? this : this.parent_scope.resolve();
|
|
||||||
},
|
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
|
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
|
||||||
},
|
},
|
||||||
@@ -1837,7 +1837,7 @@ var AST_Label = DEFNODE("Label", "references", {
|
|||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.references = [];
|
this.references = [];
|
||||||
this.thedef = this;
|
this.thedef = this;
|
||||||
}
|
},
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
|
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
|
||||||
@@ -2039,16 +2039,21 @@ TreeWalker.prototype = {
|
|||||||
return this.stack[this.stack.length - 2 - (n || 0)];
|
return this.stack[this.stack.length - 2 - (n || 0)];
|
||||||
},
|
},
|
||||||
push: function(node) {
|
push: function(node) {
|
||||||
if (node instanceof AST_Lambda) {
|
var value;
|
||||||
|
if (node instanceof AST_Class) {
|
||||||
|
this.directives = Object.create(this.directives);
|
||||||
|
value = "use strict";
|
||||||
|
} else if (node instanceof AST_Directive) {
|
||||||
|
value = node.value;
|
||||||
|
} else if (node instanceof AST_Lambda) {
|
||||||
this.directives = Object.create(this.directives);
|
this.directives = Object.create(this.directives);
|
||||||
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
|
|
||||||
this.directives[node.value] = node;
|
|
||||||
}
|
}
|
||||||
|
if (value && !this.directives[value]) this.directives[value] = node;
|
||||||
this.stack.push(node);
|
this.stack.push(node);
|
||||||
},
|
},
|
||||||
pop: function() {
|
pop: function() {
|
||||||
var node = this.stack.pop();
|
var node = this.stack.pop();
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Class || node instanceof AST_Lambda) {
|
||||||
this.directives = Object.getPrototypeOf(this.directives);
|
this.directives = Object.getPrototypeOf(this.directives);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
376
lib/compress.js
376
lib/compress.js
@@ -80,6 +80,7 @@ function Compressor(options, false_by_default) {
|
|||||||
keep_infinity : false,
|
keep_infinity : false,
|
||||||
loops : !false_by_default,
|
loops : !false_by_default,
|
||||||
merge_vars : !false_by_default,
|
merge_vars : !false_by_default,
|
||||||
|
module : false,
|
||||||
negate_iife : !false_by_default,
|
negate_iife : !false_by_default,
|
||||||
objects : !false_by_default,
|
objects : !false_by_default,
|
||||||
optional_chains : !false_by_default,
|
optional_chains : !false_by_default,
|
||||||
@@ -97,7 +98,7 @@ function Compressor(options, false_by_default) {
|
|||||||
switches : !false_by_default,
|
switches : !false_by_default,
|
||||||
templates : !false_by_default,
|
templates : !false_by_default,
|
||||||
top_retain : null,
|
top_retain : null,
|
||||||
toplevel : !!(options && options["top_retain"]),
|
toplevel : !!(options && (options["module"] || options["top_retain"])),
|
||||||
typeofs : !false_by_default,
|
typeofs : !false_by_default,
|
||||||
unsafe : false,
|
unsafe : false,
|
||||||
unsafe_comps : false,
|
unsafe_comps : false,
|
||||||
@@ -130,6 +131,7 @@ function Compressor(options, false_by_default) {
|
|||||||
var escaped = def.escaped;
|
var escaped = def.escaped;
|
||||||
return escaped && escaped.depth != 1;
|
return escaped && escaped.depth != 1;
|
||||||
};
|
};
|
||||||
|
if (this.options["module"]) this.directives["use strict"] = true;
|
||||||
var pure_funcs = this.options["pure_funcs"];
|
var pure_funcs = this.options["pure_funcs"];
|
||||||
if (typeof pure_funcs == "function") {
|
if (typeof pure_funcs == "function") {
|
||||||
this.pure_funcs = pure_funcs;
|
this.pure_funcs = pure_funcs;
|
||||||
@@ -649,7 +651,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
if (!HOP(tw.safe_ids, def.id)) {
|
if (!HOP(tw.safe_ids, def.id)) {
|
||||||
if (!safe) return false;
|
if (!safe) return false;
|
||||||
if (safe.read) {
|
if (safe.read || tw.in_loop) {
|
||||||
var scope = tw.find_parent(AST_BlockScope);
|
var scope = tw.find_parent(AST_BlockScope);
|
||||||
if (scope instanceof AST_Class) return false;
|
if (scope instanceof AST_Class) return false;
|
||||||
if (def.scope.resolve() !== scope.resolve()) return false;
|
if (def.scope.resolve() !== scope.resolve()) return false;
|
||||||
@@ -766,14 +768,14 @@ Compressor.prototype.compress = function(node) {
|
|||||||
function make_fixed_default(compressor, node, save) {
|
function make_fixed_default(compressor, node, save) {
|
||||||
var prev_save, prev_seq;
|
var prev_save, prev_seq;
|
||||||
return function() {
|
return function() {
|
||||||
|
if (prev_seq === node) return node;
|
||||||
var current = save();
|
var current = save();
|
||||||
var ev;
|
var ev = fuzzy_eval(compressor, current, true);
|
||||||
if (!is_undefined(current, compressor) && (ev = fuzzy_eval(compressor, current, true)) !== undefined) {
|
if (ev instanceof AST_Node) {
|
||||||
return ev instanceof AST_Node ? node : current;
|
prev_seq = node;
|
||||||
}
|
} else if (prev_save !== current) {
|
||||||
if (prev_save !== current) {
|
|
||||||
prev_save = current;
|
prev_save = current;
|
||||||
prev_seq = make_sequence(node, [ current, node.value ]);
|
prev_seq = ev === undefined ? make_sequence(node, [ current, node.value ]) : current;
|
||||||
}
|
}
|
||||||
return prev_seq;
|
return prev_seq;
|
||||||
};
|
};
|
||||||
@@ -1557,7 +1559,10 @@ Compressor.prototype.compress = function(node) {
|
|||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("is_immutable", function() {
|
AST_SymbolRef.DEFMETHOD("is_immutable", function() {
|
||||||
var def = this.redef || this.definition();
|
var def = this.redef || this.definition();
|
||||||
return (this.in_arg || def.orig.length == 1) && def.orig[0] instanceof AST_SymbolLambda;
|
if (!(def.orig[0] instanceof AST_SymbolLambda)) return false;
|
||||||
|
if (def.orig.length == 1) return true;
|
||||||
|
if (!this.in_arg) return false;
|
||||||
|
return !(def.orig[1] instanceof AST_SymbolFunarg);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("convert_symbol", noop);
|
AST_Node.DEFMETHOD("convert_symbol", noop);
|
||||||
@@ -2464,6 +2469,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
abort = false;
|
abort = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Class) {
|
||||||
|
if (!in_try) return false;
|
||||||
|
var base = node.extends;
|
||||||
|
if (!base) return false;
|
||||||
|
if (base instanceof AST_SymbolRef) base = base.fixed_value();
|
||||||
|
return !safe_for_extends(base);
|
||||||
|
}
|
||||||
if (node instanceof AST_Exit) {
|
if (node instanceof AST_Exit) {
|
||||||
if (in_try) {
|
if (in_try) {
|
||||||
if (in_try.bfinally) return true;
|
if (in_try.bfinally) return true;
|
||||||
@@ -2552,8 +2564,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& all(iife.args, function(arg) {
|
&& all(iife.args, function(arg) {
|
||||||
return !(arg instanceof AST_Spread);
|
return !(arg instanceof AST_Spread);
|
||||||
})) {
|
})) {
|
||||||
var fn_strict = compressor.has_directive("use strict");
|
var fn_strict = fn.in_strict_mode(compressor)
|
||||||
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
|
&& !fn.parent_scope.resolve(true).in_strict_mode(compressor);
|
||||||
var has_await = is_async(fn) ? function(node) {
|
var has_await = is_async(fn) ? function(node) {
|
||||||
return node instanceof AST_Symbol && node.name == "await";
|
return node instanceof AST_Symbol && node.name == "await";
|
||||||
} : function(node) {
|
} : function(node) {
|
||||||
@@ -4120,6 +4132,25 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& !(compressor && node.expression.has_side_effects(compressor));
|
&& !(compressor && node.expression.has_side_effects(compressor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in_strict_mode()
|
||||||
|
// return true if scope executes in Strict Mode
|
||||||
|
(function(def) {
|
||||||
|
def(AST_Class, return_true);
|
||||||
|
def(AST_Scope, function(compressor) {
|
||||||
|
var body = this.body;
|
||||||
|
for (var i = 0; i < body.length; i++) {
|
||||||
|
var stat = body[i];
|
||||||
|
if (!(stat instanceof AST_Directive)) break;
|
||||||
|
if (stat.value == "use strict") return true;
|
||||||
|
}
|
||||||
|
var parent = this.parent_scope;
|
||||||
|
if (!parent) return compressor.option("module");
|
||||||
|
return parent.resolve(true).in_strict_mode(compressor);
|
||||||
|
});
|
||||||
|
})(function(node, func) {
|
||||||
|
node.DEFMETHOD("in_strict_mode", func);
|
||||||
|
});
|
||||||
|
|
||||||
// is_truthy()
|
// is_truthy()
|
||||||
// return true if `!!node === true`
|
// return true if `!!node === true`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
@@ -6015,7 +6046,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var NO_MERGE = makePredicate("arguments await yield");
|
var NO_MERGE = makePredicate("arguments await yield");
|
||||||
AST_Scope.DEFMETHOD("merge_variables", function(compressor) {
|
AST_Scope.DEFMETHOD("merge_variables", function(compressor) {
|
||||||
if (!compressor.option("merge_vars")) return;
|
if (!compressor.option("merge_vars")) return;
|
||||||
var in_try, root, segment = {}, self = this;
|
var in_arg = [], in_try, root, segment = {}, self = this;
|
||||||
var first = [], last = [], index = 0;
|
var first = [], last = [], index = 0;
|
||||||
var declarations = new Dictionary();
|
var declarations = new Dictionary();
|
||||||
var references = Object.create(null);
|
var references = Object.create(null);
|
||||||
@@ -6026,31 +6057,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var rhs = node.right;
|
var rhs = node.right;
|
||||||
if (lhs instanceof AST_Destructured) {
|
if (lhs instanceof AST_Destructured) {
|
||||||
rhs.walk(tw);
|
rhs.walk(tw);
|
||||||
var marker = new TreeWalker(function(node) {
|
walk_destructured(AST_SymbolRef, mark, lhs);
|
||||||
if (node instanceof AST_Destructured) return;
|
|
||||||
if (node instanceof AST_DefaultValue) {
|
|
||||||
push();
|
|
||||||
node.value.walk(tw);
|
|
||||||
pop();
|
|
||||||
node.name.walk(marker);
|
|
||||||
} else if (node instanceof AST_DestructuredKeyVal) {
|
|
||||||
if (node.key instanceof AST_Node) {
|
|
||||||
push();
|
|
||||||
segment.block = node;
|
|
||||||
node.key.walk(tw);
|
|
||||||
node.value.walk(marker);
|
|
||||||
pop();
|
|
||||||
} else {
|
|
||||||
node.value.walk(marker);
|
|
||||||
}
|
|
||||||
} else if (node instanceof AST_SymbolRef) {
|
|
||||||
mark(node);
|
|
||||||
} else {
|
|
||||||
node.walk(tw);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
lhs.walk(marker);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (lazy_op[node.operator.slice(0, -1)]) {
|
if (lazy_op[node.operator.slice(0, -1)]) {
|
||||||
@@ -6081,18 +6088,15 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
var exp = node.expression;
|
var exp = node.expression;
|
||||||
var tail = exp.tail_node();
|
if (exp instanceof AST_LambdaExpression) {
|
||||||
if (!(tail instanceof AST_LambdaExpression)) {
|
node.args.forEach(function(arg) {
|
||||||
|
arg.walk(tw);
|
||||||
|
});
|
||||||
|
exp.walk(tw);
|
||||||
|
} else {
|
||||||
descend();
|
descend();
|
||||||
return mark_expression(exp);
|
mark_expression(exp);
|
||||||
}
|
}
|
||||||
if (exp !== tail) exp.expressions.slice(0, -1).forEach(function(node) {
|
|
||||||
node.walk(tw);
|
|
||||||
});
|
|
||||||
node.args.forEach(function(arg) {
|
|
||||||
arg.walk(tw);
|
|
||||||
});
|
|
||||||
tail.walk(tw);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Class) {
|
if (node instanceof AST_Class) {
|
||||||
@@ -6105,9 +6109,10 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (prop.static) {
|
if (prop.static) {
|
||||||
prop.value.walk(tw);
|
prop.value.walk(tw);
|
||||||
} else {
|
} else {
|
||||||
push(tw);
|
push();
|
||||||
|
segment.block = node;
|
||||||
prop.value.walk(tw);
|
prop.value.walk(tw);
|
||||||
pop(tw);
|
pop();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@@ -6173,32 +6178,16 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
if (node.name) references[node.name.definition().id] = false;
|
if (node.name) references[node.name.definition().id] = false;
|
||||||
var marker = node.uses_arguments && !tw.has_directive("use strict") ? function(node) {
|
var marker = node.uses_arguments && !tw.has_directive("use strict") ? function(node) {
|
||||||
if (node instanceof AST_SymbolFunarg) references[node.definition().id] = false;
|
references[node.definition().id] = false;
|
||||||
} : function(node) {
|
} : function(node) {
|
||||||
if (node instanceof AST_SymbolFunarg) mark(node);
|
mark(node);
|
||||||
};
|
};
|
||||||
var scanner = new TreeWalker(function(ref) {
|
in_arg.push(node);
|
||||||
if (ref instanceof AST_SymbolDeclaration) references[ref.definition().id] = false;
|
|
||||||
if (!(ref instanceof AST_SymbolRef)) return;
|
|
||||||
var def = ref.definition();
|
|
||||||
var ldef = node.variables.get(ref.name);
|
|
||||||
if (ldef && (ldef === def
|
|
||||||
|| def.undeclared
|
|
||||||
|| node.parent_scope.find_variable(ref.name) === def)) {
|
|
||||||
references[def.id] = false;
|
|
||||||
references[ldef.id] = false;
|
|
||||||
} else {
|
|
||||||
var save = segment;
|
|
||||||
pop();
|
|
||||||
mark(ref, true);
|
|
||||||
segment = save;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
node.argnames.forEach(function(argname) {
|
node.argnames.forEach(function(argname) {
|
||||||
argname.mark_symbol(marker, scanner);
|
walk_destructured(AST_SymbolFunarg, marker, argname);
|
||||||
});
|
});
|
||||||
if (node.rest) node.rest.mark_symbol(marker, scanner);
|
if (node.rest) walk_destructured(AST_SymbolFunarg, marker, node.rest);
|
||||||
|
in_arg.pop();
|
||||||
}
|
}
|
||||||
walk_lambda(node, tw);
|
walk_lambda(node, tw);
|
||||||
pop();
|
pop();
|
||||||
@@ -6214,7 +6203,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
} else {
|
} else {
|
||||||
descend();
|
descend();
|
||||||
}
|
}
|
||||||
return mark_expression(exp);
|
mark_expression(exp);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Switch) {
|
if (node instanceof AST_Switch) {
|
||||||
node.expression.walk(tw);
|
node.expression.walk(tw);
|
||||||
@@ -6246,9 +6236,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (node instanceof AST_Try) {
|
if (node instanceof AST_Try) {
|
||||||
var save_try = in_try;
|
var save_try = in_try;
|
||||||
in_try = node;
|
in_try = node;
|
||||||
var save = segment;
|
|
||||||
walk_body(node, tw);
|
walk_body(node, tw);
|
||||||
segment = save;
|
|
||||||
if (node.bcatch) {
|
if (node.bcatch) {
|
||||||
if (node.bcatch.argname) node.bcatch.argname.mark_symbol(function(node) {
|
if (node.bcatch.argname) node.bcatch.argname.mark_symbol(function(node) {
|
||||||
if (node instanceof AST_SymbolCatch) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
@@ -6266,7 +6254,6 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
in_try = save_try;
|
in_try = save_try;
|
||||||
segment = save;
|
|
||||||
if (node.bfinally) node.bfinally.walk(tw);
|
if (node.bfinally) node.bfinally.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -6316,11 +6303,9 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mark_expression(exp) {
|
function mark_expression(exp) {
|
||||||
if (compressor.option("ie")) {
|
if (!compressor.option("ie")) return;
|
||||||
var sym = root_expr(exp);
|
var sym = root_expr(exp);
|
||||||
if (sym instanceof AST_SymbolRef) sym.walk(tw);
|
if (sym instanceof AST_SymbolRef) sym.walk(tw);
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function walk_cond(condition, consequent, alternative) {
|
function walk_cond(condition, consequent, alternative) {
|
||||||
@@ -6416,8 +6401,45 @@ Compressor.prototype.compress = function(node) {
|
|||||||
segment = Object.getPrototypeOf(segment);
|
segment = Object.getPrototypeOf(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function walk_destructured(symbol_type, mark, lhs) {
|
||||||
|
var marker = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Destructured) return;
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
push();
|
||||||
|
node.value.walk(tw);
|
||||||
|
pop();
|
||||||
|
node.name.walk(marker);
|
||||||
|
} else if (node instanceof AST_DestructuredKeyVal) {
|
||||||
|
if (node.key instanceof AST_Node) {
|
||||||
|
push();
|
||||||
|
segment.block = node;
|
||||||
|
node.key.walk(tw);
|
||||||
|
node.value.walk(marker);
|
||||||
|
pop();
|
||||||
|
} else {
|
||||||
|
node.value.walk(marker);
|
||||||
|
}
|
||||||
|
} else if (node instanceof symbol_type) {
|
||||||
|
mark(node);
|
||||||
|
} else {
|
||||||
|
node.walk(tw);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
lhs.walk(marker);
|
||||||
|
}
|
||||||
|
|
||||||
function mark(sym, read) {
|
function mark(sym, read) {
|
||||||
var def = sym.definition(), ldef, seg = segment;
|
var def = sym.definition(), ldef;
|
||||||
|
if (read && !all(in_arg, function(fn) {
|
||||||
|
ldef = fn.variables.get(sym.name);
|
||||||
|
if (!ldef) return true;
|
||||||
|
if (!is_funarg(ldef)) return true;
|
||||||
|
return ldef !== def
|
||||||
|
&& !def.undeclared
|
||||||
|
&& fn.parent_scope.find_variable(sym.name) !== def;
|
||||||
|
})) return references[def.id] = references[ldef.id] = false;
|
||||||
|
var seg = segment;
|
||||||
if (in_try) {
|
if (in_try) {
|
||||||
push();
|
push();
|
||||||
seg = segment;
|
seg = segment;
|
||||||
@@ -6776,7 +6798,6 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var unused_fn_names = [];
|
|
||||||
var calls_to_drop_args = [];
|
var calls_to_drop_args = [];
|
||||||
var fns_with_marked_args = [];
|
var fns_with_marked_args = [];
|
||||||
var trimmer = new TreeTransformer(function(node) {
|
var trimmer = new TreeTransformer(function(node) {
|
||||||
@@ -6897,7 +6918,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_ClassExpression && node.name && drop_fn_name(node.name.definition())) {
|
if (node instanceof AST_ClassExpression && node.name && drop_fn_name(node.name.definition())) {
|
||||||
unused_fn_names.push(node);
|
node.name = null;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
if (drop_funcs && node !== self && node instanceof AST_LambdaDefinition) {
|
if (drop_funcs && node !== self && node instanceof AST_LambdaDefinition) {
|
||||||
@@ -6913,7 +6934,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LambdaExpression && node.name && drop_fn_name(node.name.definition())) {
|
if (node instanceof AST_LambdaExpression && node.name && drop_fn_name(node.name.definition())) {
|
||||||
unused_fn_names.push(node);
|
node.name = null;
|
||||||
}
|
}
|
||||||
if (!(node instanceof AST_Accessor)) {
|
if (!(node instanceof AST_Accessor)) {
|
||||||
var args, spread, trim = compressor.drop_fargs(node, parent);
|
var args, spread, trim = compressor.drop_fargs(node, parent);
|
||||||
@@ -6925,7 +6946,9 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
var argnames = node.argnames;
|
var argnames = node.argnames;
|
||||||
var rest = node.rest;
|
var rest = node.rest;
|
||||||
|
var after = false, before = false;
|
||||||
if (rest) {
|
if (rest) {
|
||||||
|
before = true;
|
||||||
if (!args || spread < argnames.length || rest instanceof AST_SymbolFunarg) {
|
if (!args || spread < argnames.length || rest instanceof AST_SymbolFunarg) {
|
||||||
rest = rest.transform(trimmer);
|
rest = rest.transform(trimmer);
|
||||||
} else {
|
} else {
|
||||||
@@ -6938,8 +6961,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
args.length = argnames.length;
|
args.length = argnames.length;
|
||||||
if (trimmed.value.elements.length) [].push.apply(args, trimmed.value.elements);
|
if (trimmed.value.elements.length) [].push.apply(args, trimmed.value.elements);
|
||||||
}
|
}
|
||||||
if (rest instanceof AST_Destructured && !rest.rest
|
if (rest instanceof AST_Destructured && !rest.rest) {
|
||||||
&& (!node.uses_arguments || tt.has_directive("use strict"))) {
|
|
||||||
if (rest instanceof AST_DestructuredArray) {
|
if (rest instanceof AST_DestructuredArray) {
|
||||||
if (rest.elements.length == 0) rest = null;
|
if (rest.elements.length == 0) rest = null;
|
||||||
} else if (rest.properties.length == 0) {
|
} else if (rest.properties.length == 0) {
|
||||||
@@ -6947,9 +6969,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.rest = rest;
|
node.rest = rest;
|
||||||
if (rest) trim = false;
|
if (rest) {
|
||||||
|
trim = false;
|
||||||
|
after = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var default_length = trim ? -1 : node.length();
|
var default_length = trim ? -1 : node.length();
|
||||||
|
var trim_value = args && !node.uses_arguments && parent !== compressor.parent();
|
||||||
for (var i = argnames.length; --i >= 0;) {
|
for (var i = argnames.length; --i >= 0;) {
|
||||||
var sym = argnames[i];
|
var sym = argnames[i];
|
||||||
if (sym instanceof AST_SymbolFunarg) {
|
if (sym instanceof AST_SymbolFunarg) {
|
||||||
@@ -6964,29 +6990,43 @@ Compressor.prototype.compress = function(node) {
|
|||||||
sym.unused = true;
|
sym.unused = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
before = true;
|
||||||
var funarg;
|
var funarg;
|
||||||
if (!args || spread < i) {
|
if (!args || spread < i) {
|
||||||
funarg = sym.transform(trimmer);
|
funarg = sym.transform(trimmer);
|
||||||
} else {
|
} else {
|
||||||
funarg = trim_destructured(sym, args[i], function(node) {
|
var trimmed = trim_destructured(sym, args[i], function(node) {
|
||||||
return node.definition().id in in_use_ids ? node : null;
|
return node.definition().id in in_use_ids ? node : null;
|
||||||
}, !node.uses_arguments, sym).name;
|
}, trim_value, sym);
|
||||||
|
funarg = trimmed.name;
|
||||||
|
if (trimmed.value) args[i] = trimmed.value;
|
||||||
}
|
}
|
||||||
if (funarg) {
|
if (funarg) {
|
||||||
trim = false;
|
trim = false;
|
||||||
|
argnames[i] = funarg;
|
||||||
|
if (!after) after = !(funarg instanceof AST_SymbolFunarg);
|
||||||
} else if (trim) {
|
} else if (trim) {
|
||||||
log_default(sym, "Dropping unused default argument {name}");
|
log_default(sym, "Dropping unused default argument {name}");
|
||||||
argnames.pop();
|
argnames.pop();
|
||||||
} else if (i > default_length) {
|
} else if (i > default_length) {
|
||||||
log_default(sym, "Dropping unused default argument assignment {name}");
|
log_default(sym, "Dropping unused default argument assignment {name}");
|
||||||
if (sym.name instanceof AST_SymbolFunarg) sym.name.unused = true;
|
if (sym.name instanceof AST_SymbolFunarg) {
|
||||||
|
sym.name.unused = true;
|
||||||
|
} else {
|
||||||
|
after = true;
|
||||||
|
}
|
||||||
argnames[i] = sym.name;
|
argnames[i] = sym.name;
|
||||||
} else {
|
} else {
|
||||||
log_default(sym, "Dropping unused default argument value {name}");
|
log_default(sym, "Dropping unused default argument value {name}");
|
||||||
|
argnames[i] = sym = sym.clone();
|
||||||
sym.value = make_node(AST_Number, sym, { value: 0 });
|
sym.value = make_node(AST_Number, sym, { value: 0 });
|
||||||
|
after = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (before && !after && node.uses_arguments && !tt.has_directive("use strict")) {
|
||||||
|
node.rest = make_node(AST_DestructuredArray, node, { elements: [] });
|
||||||
|
}
|
||||||
fns_with_marked_args.push(node);
|
fns_with_marked_args.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7210,6 +7250,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
});
|
});
|
||||||
var index = indexOf_assign(sym, def);
|
var index = indexOf_assign(sym, def);
|
||||||
if (index >= 0) assign_in_use[sym.id][index] = assign;
|
if (index >= 0) assign_in_use[sym.id][index] = assign;
|
||||||
|
sym.assignments++;
|
||||||
sym.eliminated++;
|
sym.eliminated++;
|
||||||
return assign;
|
return assign;
|
||||||
}));
|
}));
|
||||||
@@ -7285,6 +7326,13 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
}, function(node, in_list) {
|
}, function(node, in_list) {
|
||||||
if (node instanceof AST_BlockStatement) return trim_block(node, tt.parent(), in_list);
|
if (node instanceof AST_BlockStatement) return trim_block(node, tt.parent(), in_list);
|
||||||
|
if (node instanceof AST_ExportDeclaration) {
|
||||||
|
var block = node.body;
|
||||||
|
if (!(block instanceof AST_BlockStatement)) return;
|
||||||
|
node.body = block.body.pop();
|
||||||
|
block.body.push(node);
|
||||||
|
return in_list ? List.splice(block.body) : block;
|
||||||
|
}
|
||||||
if (node instanceof AST_For) return patch_for_init(node, in_list);
|
if (node instanceof AST_For) return patch_for_init(node, in_list);
|
||||||
if (node instanceof AST_ForIn) {
|
if (node instanceof AST_ForIn) {
|
||||||
if (!drop_vars || !compressor.option("loops")) return;
|
if (!drop_vars || !compressor.option("loops")) return;
|
||||||
@@ -7318,6 +7366,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
tt.push(compressor.parent());
|
tt.push(compressor.parent());
|
||||||
|
tt.directives = Object.create(compressor.directives);
|
||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
if (self instanceof AST_Lambda
|
if (self instanceof AST_Lambda
|
||||||
&& self.body.length == 1
|
&& self.body.length == 1
|
||||||
@@ -7325,9 +7374,6 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& self.body[0].value == "use strict") {
|
&& self.body[0].value == "use strict") {
|
||||||
self.body.length = 0;
|
self.body.length = 0;
|
||||||
}
|
}
|
||||||
unused_fn_names.forEach(function(fn) {
|
|
||||||
fn.name = null;
|
|
||||||
});
|
|
||||||
calls_to_drop_args.forEach(function(call) {
|
calls_to_drop_args.forEach(function(call) {
|
||||||
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
||||||
});
|
});
|
||||||
@@ -7539,6 +7585,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var value = node.value.drop_side_effect_free(compressor);
|
var value = node.value.drop_side_effect_free(compressor);
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
log(node.name, "Side effects in default value of unused variable {name}");
|
log(node.name, "Side effects in default value of unused variable {name}");
|
||||||
|
node = node.clone();
|
||||||
node.name.unused = null;
|
node.name.unused = null;
|
||||||
node.value = value;
|
node.value = value;
|
||||||
}
|
}
|
||||||
@@ -7616,6 +7663,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
drop = save_drop;
|
drop = save_drop;
|
||||||
if (values && newValues) {
|
if (values && newValues) {
|
||||||
fill_holes(value, newValues);
|
fill_holes(value, newValues);
|
||||||
|
value = value.clone();
|
||||||
value.elements = newValues;
|
value.elements = newValues;
|
||||||
}
|
}
|
||||||
if (!node.rest && (value instanceof AST_Array
|
if (!node.rest && (value instanceof AST_Array
|
||||||
@@ -7649,20 +7697,25 @@ Compressor.prototype.compress = function(node) {
|
|||||||
drop = false;
|
drop = false;
|
||||||
value = value.fixed_value();
|
value = value.fixed_value();
|
||||||
}
|
}
|
||||||
var prop_keys, prop_map;
|
var prop_keys, prop_map, values;
|
||||||
if (value instanceof AST_Object) {
|
if (value instanceof AST_Object) {
|
||||||
prop_keys = [];
|
prop_keys = [];
|
||||||
prop_map = new Dictionary();
|
prop_map = new Dictionary();
|
||||||
value.properties.forEach(function(prop, index) {
|
values = value.properties.map(function(prop, index) {
|
||||||
if (prop instanceof AST_Spread) return prop_map = false;
|
prop = prop.clone();
|
||||||
var key = prop.key;
|
if (prop instanceof AST_Spread) {
|
||||||
if (key instanceof AST_Node) key = key.evaluate(compressor, true);
|
|
||||||
if (key instanceof AST_Node) {
|
|
||||||
prop_map = false;
|
prop_map = false;
|
||||||
} else if (prop_map && !(prop instanceof AST_ObjectSetter)) {
|
} else {
|
||||||
prop_map.set(key, prop);
|
var key = prop.key;
|
||||||
|
if (key instanceof AST_Node) key = key.evaluate(compressor, true);
|
||||||
|
if (key instanceof AST_Node) {
|
||||||
|
prop_map = false;
|
||||||
|
} else if (prop_map && !(prop instanceof AST_ObjectSetter)) {
|
||||||
|
prop_map.set(key, prop);
|
||||||
|
}
|
||||||
|
prop_keys[index] = key;
|
||||||
}
|
}
|
||||||
prop_keys[index] = key;
|
return prop;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (node.rest) {
|
if (node.rest) {
|
||||||
@@ -7727,27 +7780,30 @@ Compressor.prototype.compress = function(node) {
|
|||||||
});
|
});
|
||||||
value = save_value;
|
value = save_value;
|
||||||
drop = save_drop;
|
drop = save_drop;
|
||||||
if (drop_keys && prop_keys) value.properties = List(value.properties, function(prop, index) {
|
if (drop_keys && prop_keys) {
|
||||||
if (prop instanceof AST_Spread) return prop;
|
value = value.clone();
|
||||||
var key = prop_keys[index];
|
value.properties = List(values, function(prop, index) {
|
||||||
if (key instanceof AST_Node) return prop;
|
if (prop instanceof AST_Spread) return prop;
|
||||||
if (drop_keys.has(key)) {
|
var key = prop_keys[index];
|
||||||
var mapped = drop_keys.get(key);
|
if (key instanceof AST_Node) return prop;
|
||||||
if (!mapped) return prop;
|
if (drop_keys.has(key)) {
|
||||||
if (mapped === prop) return prop_map.get(key) || List.skip;
|
var mapped = drop_keys.get(key);
|
||||||
} else if (node.rest) {
|
if (!mapped) return prop;
|
||||||
return prop;
|
if (mapped === prop) return prop_map.get(key) || List.skip;
|
||||||
}
|
} else if (node.rest) {
|
||||||
var trimmed = prop.value.drop_side_effect_free(compressor);
|
return prop;
|
||||||
if (trimmed) {
|
}
|
||||||
prop.value = trimmed;
|
var trimmed = prop.value.drop_side_effect_free(compressor);
|
||||||
return prop;
|
if (trimmed) {
|
||||||
}
|
prop.value = trimmed;
|
||||||
return retain_key(prop) ? make_node(AST_ObjectKeyVal, prop, {
|
return prop;
|
||||||
key: prop.key,
|
}
|
||||||
value: make_node(AST_Number, prop, { value: 0 }),
|
return retain_key(prop) ? make_node(AST_ObjectKeyVal, prop, {
|
||||||
}) : List.skip;
|
key: prop.key,
|
||||||
});
|
value: make_node(AST_Number, prop, { value: 0 }),
|
||||||
|
}) : List.skip;
|
||||||
|
});
|
||||||
|
}
|
||||||
if (value && !node.rest) switch (properties.length) {
|
if (value && !node.rest) switch (properties.length) {
|
||||||
case 0:
|
case 0:
|
||||||
if (node === root) break;
|
if (node === root) break;
|
||||||
@@ -8140,12 +8196,12 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
|
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
|
||||||
var defs_by_id = Object.create(null);
|
var defs_by_id = Object.create(null);
|
||||||
self.transform(new TreeTransformer(function(node, descend) {
|
var tt = new TreeTransformer(function(node, descend) {
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
if (node.operator != "=") return;
|
if (node.operator != "=") return;
|
||||||
if (!node.write_only) return;
|
if (!node.write_only) return;
|
||||||
if (!can_hoist(node.left, node.right, 1)) return;
|
if (!can_hoist(node.left, node.right, 1)) return;
|
||||||
descend(node, this);
|
descend(node, tt);
|
||||||
var defs = new Dictionary();
|
var defs = new Dictionary();
|
||||||
var assignments = [];
|
var assignments = [];
|
||||||
var decls = [];
|
var decls = [];
|
||||||
@@ -8169,15 +8225,20 @@ Compressor.prototype.compress = function(node) {
|
|||||||
});
|
});
|
||||||
defs.value = node.right;
|
defs.value = node.right;
|
||||||
defs_by_id[node.left.definition().id] = defs;
|
defs_by_id[node.left.definition().id] = defs;
|
||||||
self.body.splice(self.body.indexOf(this.stack[1]) + 1, 0, make_node(AST_Var, node, {
|
self.body.splice(self.body.indexOf(tt.stack[1]) + 1, 0, make_node(AST_Var, node, {
|
||||||
definitions: decls,
|
definitions: decls,
|
||||||
}));
|
}));
|
||||||
return make_sequence(node, assignments);
|
return make_sequence(node, assignments);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) return node === self ? undefined : node;
|
if (node instanceof AST_Scope) {
|
||||||
|
if (node === self) return;
|
||||||
|
var parent = tt.parent();
|
||||||
|
if (parent.TYPE == "Call" && parent.expression === node) return;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
if (!can_hoist(node.name, node.value, 0)) return;
|
if (!can_hoist(node.name, node.value, 0)) return;
|
||||||
descend(node, this);
|
descend(node, tt);
|
||||||
var defs = new Dictionary();
|
var defs = new Dictionary();
|
||||||
var var_defs = [];
|
var var_defs = [];
|
||||||
var decl = node.clone();
|
var decl = node.clone();
|
||||||
@@ -8199,7 +8260,8 @@ Compressor.prototype.compress = function(node) {
|
|||||||
defs.set(key, new_var.definition());
|
defs.set(key, new_var.definition());
|
||||||
return new_var;
|
return new_var;
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
self.transform(tt);
|
||||||
self.transform(new TreeTransformer(function(node, descend) {
|
self.transform(new TreeTransformer(function(node, descend) {
|
||||||
if (node instanceof AST_PropAccess) {
|
if (node instanceof AST_PropAccess) {
|
||||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
if (!(node.expression instanceof AST_SymbolRef)) return;
|
||||||
@@ -8229,6 +8291,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
if (def.assignments != count) return;
|
if (def.assignments != count) return;
|
||||||
if (def.references.length - def.replaced == count) return;
|
if (def.references.length - def.replaced == count) return;
|
||||||
if (def.single_use) return;
|
if (def.single_use) return;
|
||||||
|
if (self.find_variable(sym.name) !== def) return;
|
||||||
if (top_retain(def)) return;
|
if (top_retain(def)) return;
|
||||||
if (sym.fixed_value() !== right) return;
|
if (sym.fixed_value() !== right) return;
|
||||||
var fixed = sym.fixed || def.fixed;
|
var fixed = sym.fixed || def.fixed;
|
||||||
@@ -8292,6 +8355,9 @@ Compressor.prototype.compress = function(node) {
|
|||||||
var dropped = value.drop_side_effect_free(compressor);
|
var dropped = value.drop_side_effect_free(compressor);
|
||||||
if (dropped !== value) {
|
if (dropped !== value) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
if (dropped && async && !is_primitive(compressor, dropped)) {
|
||||||
|
dropped = dropped.negate(compressor);
|
||||||
|
}
|
||||||
node.value = dropped;
|
node.value = dropped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9100,6 +9166,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
|
|
||||||
function fuzzy_eval(compressor, node, nullish) {
|
function fuzzy_eval(compressor, node, nullish) {
|
||||||
if (node.truthy) return true;
|
if (node.truthy) return true;
|
||||||
|
if (is_undefined(node)) return undefined;
|
||||||
if (node.falsy && !nullish) return false;
|
if (node.falsy && !nullish) return false;
|
||||||
if (node.is_truthy()) return true;
|
if (node.is_truthy()) return true;
|
||||||
return node.evaluate(compressor, true);
|
return node.evaluate(compressor, true);
|
||||||
@@ -9114,17 +9181,20 @@ Compressor.prototype.compress = function(node) {
|
|||||||
child = parent;
|
child = parent;
|
||||||
parent = compressor.parent(level++);
|
parent = compressor.parent(level++);
|
||||||
if (parent instanceof AST_Binary) {
|
if (parent instanceof AST_Binary) {
|
||||||
var op = parent.operator;
|
switch (child) {
|
||||||
if (!lazy_op[op]) return;
|
case parent.left:
|
||||||
var left = parent.left;
|
if (lazy_op[parent.operator]) continue;
|
||||||
if (left === child) continue;
|
|
||||||
if (match(left)) switch (op) {
|
|
||||||
case "&&":
|
|
||||||
node[negated ? "falsy" : "truthy"] = true;
|
|
||||||
break;
|
break;
|
||||||
case "||":
|
case parent.right:
|
||||||
case "??":
|
if (match(parent.left)) switch (parent.operator) {
|
||||||
node[negated ? "truthy" : "falsy"] = true;
|
case "&&":
|
||||||
|
node[negated ? "falsy" : "truthy"] = true;
|
||||||
|
break;
|
||||||
|
case "||":
|
||||||
|
case "??":
|
||||||
|
node[negated ? "truthy" : "falsy"] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (parent instanceof AST_Conditional) {
|
} else if (parent instanceof AST_Conditional) {
|
||||||
@@ -9884,6 +9954,10 @@ Compressor.prototype.compress = function(node) {
|
|||||||
return safe;
|
return safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function safe_from_strict_mode(fn, compressor) {
|
||||||
|
return fn.in_strict_mode(compressor) || !compressor.has_directive("use strict");
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor) {
|
OPT(AST_Call, function(self, compressor) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
var terminated = trim_optional_chain(self, compressor);
|
var terminated = trim_optional_chain(self, compressor);
|
||||||
@@ -10208,7 +10282,10 @@ Compressor.prototype.compress = function(node) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest));
|
}) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest));
|
||||||
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
|
var can_inline = can_drop
|
||||||
|
&& compressor.option("inline")
|
||||||
|
&& !self.is_expr_pure(compressor)
|
||||||
|
&& (exp === fn || safe_from_strict_mode(fn, compressor));
|
||||||
if (can_inline && stat instanceof AST_Return) {
|
if (can_inline && stat instanceof AST_Return) {
|
||||||
var value = stat.value;
|
var value = stat.value;
|
||||||
if (exp === fn
|
if (exp === fn
|
||||||
@@ -11142,9 +11219,15 @@ Compressor.prototype.compress = function(node) {
|
|||||||
&& assign instanceof AST_Assign
|
&& assign instanceof AST_Assign
|
||||||
&& assign.operator == "="
|
&& assign.operator == "="
|
||||||
&& self.left.equivalent_to(assign.left)) {
|
&& self.left.equivalent_to(assign.left)) {
|
||||||
self.right = assign.right;
|
return make_node(AST_Assign, self, {
|
||||||
assign.right = self;
|
operator: "=",
|
||||||
return assign;
|
left: assign.left,
|
||||||
|
right: make_node(AST_Binary, self, {
|
||||||
|
operator: self.operator,
|
||||||
|
left: self.left,
|
||||||
|
right: assign.right,
|
||||||
|
}),
|
||||||
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("comparisons")) switch (self.operator) {
|
if (compressor.option("comparisons")) switch (self.operator) {
|
||||||
@@ -11809,8 +11892,9 @@ Compressor.prototype.compress = function(node) {
|
|||||||
} else if (fixed.name && fixed.name.definition() !== def) {
|
} else if (fixed.name && fixed.name.definition() !== def) {
|
||||||
single_use = false;
|
single_use = false;
|
||||||
} else if (fixed.parent_scope !== self.scope || is_funarg(def)) {
|
} else if (fixed.parent_scope !== self.scope || is_funarg(def)) {
|
||||||
single_use = fixed.is_constant_expression(self.scope);
|
if (!safe_from_strict_mode(fixed, compressor)) {
|
||||||
if (single_use == "f") {
|
single_use = false;
|
||||||
|
} else if ((single_use = fixed.is_constant_expression(self.scope)) == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
do {
|
do {
|
||||||
if (scope instanceof AST_LambdaDefinition || scope instanceof AST_LambdaExpression) {
|
if (scope instanceof AST_LambdaDefinition || scope instanceof AST_LambdaExpression) {
|
||||||
@@ -13382,7 +13466,7 @@ Compressor.prototype.compress = function(node) {
|
|||||||
});
|
});
|
||||||
var body = [];
|
var body = [];
|
||||||
fn.variables.each(function(def, name) {
|
fn.variables.each(function(def, name) {
|
||||||
if (name == "arguments") return;
|
if (!arrow && name == "arguments" && def.orig.length == 1) return;
|
||||||
names.set(name, true);
|
names.set(name, true);
|
||||||
scope.enclosed.push(def);
|
scope.enclosed.push(def);
|
||||||
scope.variables.set(name, def);
|
scope.variables.set(name, def);
|
||||||
|
|||||||
@@ -81,13 +81,14 @@ function minify(files, options) {
|
|||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
keep_fnames: false,
|
keep_fnames: false,
|
||||||
mangle: {},
|
mangle: {},
|
||||||
|
module: false,
|
||||||
nameCache: null,
|
nameCache: null,
|
||||||
output: {},
|
output: {},
|
||||||
parse: {},
|
parse: {},
|
||||||
rename: undefined,
|
rename: undefined,
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
timings: false,
|
timings: false,
|
||||||
toplevel: false,
|
toplevel: !!(options && options["module"]),
|
||||||
v8: false,
|
v8: false,
|
||||||
validate: false,
|
validate: false,
|
||||||
warnings: false,
|
warnings: false,
|
||||||
@@ -101,6 +102,7 @@ function minify(files, options) {
|
|||||||
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]);
|
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]);
|
||||||
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]);
|
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]);
|
||||||
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
|
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
|
||||||
|
if (options.module) set_shorthand("module", options, [ "compress", "parse" ]);
|
||||||
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
|
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
|
||||||
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
|
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
|
||||||
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);
|
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);
|
||||||
|
|||||||
26
lib/parse.js
26
lib/parse.js
@@ -237,8 +237,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
newline_before : false,
|
newline_before : false,
|
||||||
regex_allowed : false,
|
regex_allowed : false,
|
||||||
comments_before : [],
|
comments_before : [],
|
||||||
directives : {},
|
directives : Object.create(null),
|
||||||
directive_stack : [],
|
|
||||||
read_template : with_eof_error("Unterminated template literal", function(strings) {
|
read_template : with_eof_error("Unterminated template literal", function(strings) {
|
||||||
var s = "";
|
var s = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -635,24 +634,19 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
next_token.add_directive = function(directive) {
|
next_token.add_directive = function(directive) {
|
||||||
S.directive_stack[S.directive_stack.length - 1].push(directive);
|
S.directives[directive] = true;
|
||||||
if (S.directives[directive]) S.directives[directive]++;
|
|
||||||
else S.directives[directive] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next_token.push_directives_stack = function() {
|
next_token.push_directives_stack = function() {
|
||||||
S.directive_stack.push([]);
|
S.directives = Object.create(S.directives);
|
||||||
}
|
}
|
||||||
|
|
||||||
next_token.pop_directives_stack = function() {
|
next_token.pop_directives_stack = function() {
|
||||||
var directives = S.directive_stack.pop();
|
S.directives = Object.getPrototypeOf(S.directives);
|
||||||
for (var i = directives.length; --i >= 0;) {
|
|
||||||
S.directives[directives[i]]--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next_token.has_directive = function(directive) {
|
next_token.has_directive = function(directive) {
|
||||||
return S.directives[directive] > 0;
|
return !!S.directives[directive];
|
||||||
}
|
}
|
||||||
|
|
||||||
return next_token;
|
return next_token;
|
||||||
@@ -699,6 +693,7 @@ function parse($TEXT, options) {
|
|||||||
expression : false,
|
expression : false,
|
||||||
filename : null,
|
filename : null,
|
||||||
html5_comments : true,
|
html5_comments : true,
|
||||||
|
module : false,
|
||||||
shebang : true,
|
shebang : true,
|
||||||
strict : false,
|
strict : false,
|
||||||
toplevel : null,
|
toplevel : null,
|
||||||
@@ -1340,8 +1335,6 @@ function parse($TEXT, options) {
|
|||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
var labels = S.labels;
|
var labels = S.labels;
|
||||||
++S.in_function;
|
++S.in_function;
|
||||||
S.in_directives = true;
|
|
||||||
S.input.push_directives_stack();
|
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
if (is("punc", "{")) {
|
if (is("punc", "{")) {
|
||||||
@@ -1352,8 +1345,6 @@ function parse($TEXT, options) {
|
|||||||
handle_regexp();
|
handle_regexp();
|
||||||
value = maybe_assign();
|
value = maybe_assign();
|
||||||
}
|
}
|
||||||
var is_strict = S.input.has_directive("use strict");
|
|
||||||
S.input.pop_directives_stack();
|
|
||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
@@ -1367,7 +1358,7 @@ function parse($TEXT, options) {
|
|||||||
value: value,
|
value: value,
|
||||||
end: prev(),
|
end: prev(),
|
||||||
});
|
});
|
||||||
if (is_strict) node.each_argname(strict_verify_symbol);
|
if (S.input.has_directive("use strict")) node.each_argname(strict_verify_symbol);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1412,7 +1403,7 @@ function parse($TEXT, options) {
|
|||||||
name: name,
|
name: name,
|
||||||
argnames: argnames,
|
argnames: argnames,
|
||||||
rest: argnames.rest || null,
|
rest: argnames.rest || null,
|
||||||
body: body
|
body: body,
|
||||||
});
|
});
|
||||||
if (is_strict) {
|
if (is_strict) {
|
||||||
if (name) strict_verify_symbol(name);
|
if (name) strict_verify_symbol(name);
|
||||||
@@ -2550,6 +2541,7 @@ function parse($TEXT, options) {
|
|||||||
return function() {
|
return function() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var body = [];
|
var body = [];
|
||||||
|
if (options.module) S.input.add_directive("use strict");
|
||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement());
|
body.push(statement());
|
||||||
|
|||||||
25
lib/scope.js
25
lib/scope.js
@@ -64,19 +64,20 @@ SymbolDef.prototype = {
|
|||||||
this.references.forEach(fn);
|
this.references.forEach(fn);
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
var cache = options.cache && options.cache.props;
|
if (this.mangled_name) return;
|
||||||
if (this.global && cache && cache.has(this.name)) {
|
var cache = this.global && options.cache && options.cache.props;
|
||||||
|
if (cache && cache.has(this.name)) {
|
||||||
this.mangled_name = cache.get(this.name);
|
this.mangled_name = cache.get(this.name);
|
||||||
} else if (!this.mangled_name && !this.unmangleable(options)) {
|
} else if (this.unmangleable(options)) {
|
||||||
|
names_in_use(this.scope, options).set(this.name, true);
|
||||||
|
} else {
|
||||||
var def = this.redefined();
|
var def = this.redefined();
|
||||||
if (def) {
|
if (def) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else {
|
} else {
|
||||||
this.mangled_name = next_mangled_name(this, options);
|
this.mangled_name = next_mangled_name(this, options);
|
||||||
}
|
}
|
||||||
if (this.global && cache) {
|
if (cache) cache.set(this.name, this.mangled_name);
|
||||||
cache.set(this.name, this.mangled_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
redefined: function() {
|
redefined: function() {
|
||||||
@@ -469,6 +470,7 @@ AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
|||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
this.def_variable(new AST_SymbolFunarg({
|
this.def_variable(new AST_SymbolFunarg({
|
||||||
name: "arguments",
|
name: "arguments",
|
||||||
|
scope: this,
|
||||||
start: this.start,
|
start: this.start,
|
||||||
end: this.end,
|
end: this.end,
|
||||||
}));
|
}));
|
||||||
@@ -620,14 +622,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
var lname = -1;
|
var lname = -1;
|
||||||
var redefined = [];
|
var redefined = [];
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_LabeledStatement) {
|
var save_nesting;
|
||||||
// `lname` is incremented when we get to the `AST_Label`
|
|
||||||
var save_nesting = lname;
|
|
||||||
descend();
|
|
||||||
if (!options.v8 || !in_label(tw)) lname = save_nesting;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_BlockScope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
|
// `lname` is incremented when we get to the `AST_Label`
|
||||||
|
if (node instanceof AST_LabeledStatement) save_nesting = lname;
|
||||||
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
||||||
node.init.definitions.forEach(function(defn) {
|
node.init.definitions.forEach(function(defn) {
|
||||||
defn.name.match_symbol(function(sym) {
|
defn.name.match_symbol(function(sym) {
|
||||||
@@ -673,6 +671,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
to_mangle.forEach(mangle);
|
to_mangle.forEach(mangle);
|
||||||
|
if (node instanceof AST_LabeledStatement && !(options.v8 && in_label(tw))) lname = save_nesting;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.15.4",
|
"version": "3.16.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,9 +69,7 @@ function make_code(ast, options) {
|
|||||||
function parse_test(file) {
|
function parse_test(file) {
|
||||||
var script = fs.readFileSync(file, "utf8");
|
var script = fs.readFileSync(file, "utf8");
|
||||||
try {
|
try {
|
||||||
var ast = U.parse(script, {
|
var ast = U.parse(script, { filename: file });
|
||||||
filename: file
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Caught error while parsing tests in " + file);
|
console.error("Caught error while parsing tests in " + file);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -98,14 +96,14 @@ function parse_test(file) {
|
|||||||
file: file,
|
file: file,
|
||||||
line: node.start.line,
|
line: node.start.line,
|
||||||
col: node.start.col,
|
col: node.start.col,
|
||||||
code: make_code(node, { beautify: false })
|
code: make_code(node, { beautify: false }),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_string(stat) {
|
function read_string(stat) {
|
||||||
if (stat.TYPE == "SimpleStatement") {
|
if (stat.TYPE == "SimpleStatement") {
|
||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
switch(body.TYPE) {
|
switch (body.TYPE) {
|
||||||
case "String":
|
case "String":
|
||||||
return body.value;
|
return body.value;
|
||||||
case "Array":
|
case "Array":
|
||||||
@@ -142,7 +140,7 @@ function parse_test(file) {
|
|||||||
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
|
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
name: label.name,
|
name: label.name,
|
||||||
line: label.start.line,
|
line: label.start.line,
|
||||||
col: label.start.col
|
col: label.start.col,
|
||||||
}));
|
}));
|
||||||
var stat = node.body;
|
var stat = node.body;
|
||||||
if (label.name == "expect_exact" || label.name == "node_version") {
|
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||||
@@ -155,12 +153,12 @@ function parse_test(file) {
|
|||||||
var ctor = global[body.expression.name];
|
var ctor = global[body.expression.name];
|
||||||
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||||
line: label.start.line,
|
line: label.start.line,
|
||||||
col: label.start.col
|
col: label.start.col,
|
||||||
}));
|
}));
|
||||||
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
||||||
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||||
line: label.start.line,
|
line: label.start.line,
|
||||||
col: label.start.col
|
col: label.start.col,
|
||||||
}));
|
}));
|
||||||
return node.value;
|
return node.value;
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1018,3 +1018,91 @@ issue_5356: {
|
|||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5414_1: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
if_return: true,
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(() => {
|
||||||
|
(() => {
|
||||||
|
if (!console)
|
||||||
|
var arguments = 42;
|
||||||
|
while (console.log(arguments));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => {
|
||||||
|
if (!console)
|
||||||
|
var arguments = 42;
|
||||||
|
while (console.log(arguments));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5414_2: {
|
||||||
|
options = {
|
||||||
|
arrows: true,
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(() => {
|
||||||
|
(() => {
|
||||||
|
if (!console)
|
||||||
|
var arguments = 42;
|
||||||
|
while (console.log(arguments));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(() => {
|
||||||
|
if (!console)
|
||||||
|
var arguments = 42;
|
||||||
|
while (console.log(arguments));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5416: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
loops: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f = () => {
|
||||||
|
while ((() => {
|
||||||
|
console;
|
||||||
|
var a = function g(arguments) {
|
||||||
|
console.log(arguments);
|
||||||
|
}();
|
||||||
|
})());
|
||||||
|
};
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var f = () => {
|
||||||
|
{
|
||||||
|
arguments = void 0;
|
||||||
|
console;
|
||||||
|
console.log(arguments);
|
||||||
|
var arguments;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1748,8 +1748,8 @@ issue_4454_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f(a) {
|
function f(a) {
|
||||||
(async function(c = console.log(a)) {})();
|
(async function(c = console.log(a)) {})();
|
||||||
var a = 42..toString();
|
var b = 42..toString();
|
||||||
console.log(a);
|
console.log(b);
|
||||||
}
|
}
|
||||||
f("PASS");
|
f("PASS");
|
||||||
}
|
}
|
||||||
@@ -2427,80 +2427,6 @@ issue_5023_2: {
|
|||||||
node_version: ">=8"
|
node_version: ">=8"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_5032_normal: {
|
|
||||||
options = {
|
|
||||||
merge_vars: true,
|
|
||||||
webkit: false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
async function f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS");
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
async function f(a) {
|
|
||||||
var a = log(a), c = a;
|
|
||||||
log(a);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS");
|
|
||||||
}
|
|
||||||
expect_stdout: [
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
]
|
|
||||||
node_version: ">=8"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_5032_webkit: {
|
|
||||||
options = {
|
|
||||||
merge_vars: true,
|
|
||||||
webkit: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
async function f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS");
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
async function f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS");
|
|
||||||
}
|
|
||||||
expect_stdout: [
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
]
|
|
||||||
node_version: ">=8"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_5034: {
|
issue_5034: {
|
||||||
options = {
|
options = {
|
||||||
functions: true,
|
functions: true,
|
||||||
@@ -2959,3 +2885,79 @@ issue_5305_3: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=8"
|
node_version: ">=8"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5456: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = true;
|
||||||
|
(function() {
|
||||||
|
(function(b, c) {
|
||||||
|
var d = async function() {
|
||||||
|
c = await null;
|
||||||
|
}();
|
||||||
|
var e = function() {
|
||||||
|
if (c)
|
||||||
|
console.log(typeof d);
|
||||||
|
while (b);
|
||||||
|
}();
|
||||||
|
})(function(i) {
|
||||||
|
return console.log("foo") && i;
|
||||||
|
}(a));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = true;
|
||||||
|
(function() {
|
||||||
|
b = (i = a, console.log("foo") && i),
|
||||||
|
d = async function() {
|
||||||
|
c = await null;
|
||||||
|
}(),
|
||||||
|
e = function() {
|
||||||
|
if (c) console.log(typeof d);
|
||||||
|
while (b);
|
||||||
|
}(),
|
||||||
|
void 0;
|
||||||
|
var b, c, d, e;
|
||||||
|
var i;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "foo"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5478: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
A = {
|
||||||
|
get then() {
|
||||||
|
a = "FAIL";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var a = "PASS";
|
||||||
|
(async function() {
|
||||||
|
for (var b in "foo")
|
||||||
|
return void A;
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
A = {
|
||||||
|
get then() {
|
||||||
|
a = "FAIL";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var a = "PASS";
|
||||||
|
(async function() {
|
||||||
|
for (var b in "foo")
|
||||||
|
return !A;
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|||||||
@@ -762,3 +762,27 @@ issue_5228: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5469: {
|
||||||
|
options = {
|
||||||
|
assignments: true,
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
a && 42[a = A && null];
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
a && A,
|
||||||
|
0;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ drop_extends: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_extends: {
|
keep_extends_1: {
|
||||||
options = {
|
options = {
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -366,6 +366,43 @@ keep_extends: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keep_extends_2: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(class extends Function {});
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(class extends Function {});
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_extends_3: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
class A extends Function {}
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(class extends Function {});
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
drop_name: {
|
drop_name: {
|
||||||
options = {
|
options = {
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -670,6 +707,58 @@ single_use_7: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single_use_extends: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
class A extends class B {
|
||||||
|
f() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
console.log(new A().f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(new class extends class {
|
||||||
|
f() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
} {}().f());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use_extends_non_strict: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
class A extends class B {
|
||||||
|
f() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
console.log(new A().f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(new class extends class {
|
||||||
|
f() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
} {}().f());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
collapse_non_strict: {
|
collapse_non_strict: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -742,6 +831,38 @@ collapse_rhs_static: {
|
|||||||
node_version: ">=12"
|
node_version: ">=12"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline_non_strict: {
|
||||||
|
options = {
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a.p = "PASS";
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
g() {
|
||||||
|
return f(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(new A().g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a.p = "PASS";
|
||||||
|
}
|
||||||
|
console.log(new class {
|
||||||
|
g() {
|
||||||
|
return f(42);
|
||||||
|
}
|
||||||
|
}().g());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
self_comparison: {
|
self_comparison: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
@@ -1758,12 +1879,14 @@ issue_4962_1: {
|
|||||||
})(function g() {});
|
})(function g() {});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function g() {}),
|
(function() {
|
||||||
void class {
|
function f() {
|
||||||
static c = function() {
|
|
||||||
while (console.log(typeof g));
|
while (console.log(typeof g));
|
||||||
}();
|
}
|
||||||
};
|
(class {
|
||||||
|
static c = f();
|
||||||
|
});
|
||||||
|
})(function g() {});
|
||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
node_version: ">=12"
|
node_version: ">=12"
|
||||||
@@ -1796,6 +1919,37 @@ issue_4962_1_strict: {
|
|||||||
node_version: ">=12"
|
node_version: ">=12"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4962_1_strict_direct: {
|
||||||
|
options = {
|
||||||
|
ie: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
"use strict";
|
||||||
|
while (console.log(typeof g));
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
static p = f();
|
||||||
|
}
|
||||||
|
})(function g() {});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function g() {}),
|
||||||
|
void class {
|
||||||
|
static c = function() {
|
||||||
|
"use strict";
|
||||||
|
while (console.log(typeof g));
|
||||||
|
}();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4962_2: {
|
issue_4962_2: {
|
||||||
options = {
|
options = {
|
||||||
ie: true,
|
ie: true,
|
||||||
@@ -1815,8 +1969,11 @@ issue_4962_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function f() {}(function g() {
|
console.log(function f() {}(function g() {
|
||||||
|
function h() {
|
||||||
|
f;
|
||||||
|
}
|
||||||
(class {
|
(class {
|
||||||
static c = f;
|
static c = h();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -1852,6 +2009,69 @@ issue_4962_2_strict: {
|
|||||||
node_version: ">=12"
|
node_version: ">=12"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4962_2_strict_direct: {
|
||||||
|
options = {
|
||||||
|
ie: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
function h() {
|
||||||
|
"use strict";
|
||||||
|
f;
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
static p = h();
|
||||||
|
}
|
||||||
|
}, typeof g));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
(class {
|
||||||
|
static c = function() {
|
||||||
|
"use strict";
|
||||||
|
f;
|
||||||
|
}();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4962_2_strict_direct_inline: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
ie: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
function h() {
|
||||||
|
"use strict";
|
||||||
|
f;
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
static p = h();
|
||||||
|
}
|
||||||
|
}, typeof g));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
(class {
|
||||||
|
static c = f;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4982_1: {
|
issue_4982_1: {
|
||||||
options = {
|
options = {
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
@@ -2541,7 +2761,7 @@ issue_5387: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_5389: {
|
issue_5389_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
@@ -2571,3 +2791,94 @@ issue_5389: {
|
|||||||
expect_stdout: "PASS PASS"
|
expect_stdout: "PASS PASS"
|
||||||
node_version: ">=12"
|
node_version: ">=12"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5389_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(m, n) {
|
||||||
|
console.log(m, n);
|
||||||
|
}
|
||||||
|
var a = log;
|
||||||
|
var A = class {
|
||||||
|
[a = "FAIL"] = a = "PASS";
|
||||||
|
};
|
||||||
|
var b = new A();
|
||||||
|
log(a, b.FAIL);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(m, n) {
|
||||||
|
console.log(m, n);
|
||||||
|
}
|
||||||
|
var a = log;
|
||||||
|
var A;
|
||||||
|
var b = new class {
|
||||||
|
[a = "FAIL"] = a = "PASS";
|
||||||
|
}();
|
||||||
|
log(a, b.FAIL);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS PASS"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5436: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
class A {
|
||||||
|
p = a;
|
||||||
|
}
|
||||||
|
var b = "FAIL";
|
||||||
|
A == b && b();
|
||||||
|
return new A();
|
||||||
|
}
|
||||||
|
console.log(f("PASS").p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
class A {
|
||||||
|
p = a;
|
||||||
|
}
|
||||||
|
var b = "FAIL";
|
||||||
|
A == b && b();
|
||||||
|
return new A();
|
||||||
|
}
|
||||||
|
console.log(f("PASS").p);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5481: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a = "FAIL 1", log = console.log;
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
(class extends 42 {});
|
||||||
|
log("FAIL 2", a);
|
||||||
|
} catch (e) {
|
||||||
|
log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var a = "FAIL 1", log = console.log;
|
||||||
|
try {
|
||||||
|
a = "PASS";
|
||||||
|
(class extends 42 {});
|
||||||
|
log("FAIL 2", a);
|
||||||
|
} catch (e) {
|
||||||
|
log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1855,3 +1855,20 @@ issue_5338: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5476: {
|
||||||
|
mangle = {
|
||||||
|
keep_fargs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(n) {
|
||||||
|
const a = 42;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(n) {
|
||||||
|
const o = 42;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2239,3 +2239,226 @@ issue_5407: {
|
|||||||
]
|
]
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5444_1: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
var b = function({} = setImmediate(function() {
|
||||||
|
console.log(a++);
|
||||||
|
})) {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 42;
|
||||||
|
var b = function({} = setImmediate(function() {
|
||||||
|
console.log(a++);
|
||||||
|
})) {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"42",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5444_2: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b = a++) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(f("FAIL") || "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b = a++) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(f("FAIL") || "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5444_3: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b = function(c = a *= this) {
|
||||||
|
return c;
|
||||||
|
}()) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(f("FAIL") || "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b = function(c = a *= this) {
|
||||||
|
return c;
|
||||||
|
}()) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(f("FAIL") || "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5448_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a = typeof console.log) {
|
||||||
|
do {
|
||||||
|
var b = [ ...a ];
|
||||||
|
} while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a = console.log) {
|
||||||
|
do {} while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5448_2: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a = typeof console) {
|
||||||
|
do {
|
||||||
|
var b = [ ...a ];
|
||||||
|
} while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a = 0) {
|
||||||
|
do {} while (console.log("PASS"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5448_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var [ a = typeof console ] = [ void console.log("PASS") ];
|
||||||
|
var b = [ ...a ];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5448_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var { p: a = typeof console } = { p: void console.log("PASS") };
|
||||||
|
var b = [ ...a ];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5463: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (console.log("PASS"))
|
||||||
|
var a = void 0,
|
||||||
|
b = void 0,
|
||||||
|
b = ([ a = FAIL ] = b && b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b, b;
|
||||||
|
console.log("PASS") && (
|
||||||
|
b = a = void 0,
|
||||||
|
b = [a = FAIL] = a && a
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5465: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
(function(c = b = "FAIL 2") {
|
||||||
|
this && console.log(b || "PASS");
|
||||||
|
})(42 - a && a);
|
||||||
|
}
|
||||||
|
f("FAIL 1");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = "FAIL 1",
|
||||||
|
void function(c = b = "FAIL 2") {
|
||||||
|
this && console.log(b || "PASS");
|
||||||
|
}(42 - a && a);
|
||||||
|
var a, b;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5485: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(f, a = console.log(void 0 === f ? "PASS" : "FAIL")) {})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function f(f, a = console.log(void 0 === f ? "PASS" : "FAIL")) {})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1848,8 +1848,8 @@ issue_4294: {
|
|||||||
}) {}({
|
}) {}({
|
||||||
[a]: 0,
|
[a]: 0,
|
||||||
});
|
});
|
||||||
var a = A;
|
var b = A;
|
||||||
console.log(a);
|
console.log(b);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -3020,6 +3020,7 @@ issue_5074_method_pure_getters: {
|
|||||||
issue_5085_1: {
|
issue_5085_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
@@ -3032,8 +3033,7 @@ issue_5085_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "PASS";
|
var a = "PASS";
|
||||||
var b = [ 42 ][0];
|
42;
|
||||||
b;
|
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -3043,6 +3043,7 @@ issue_5085_1: {
|
|||||||
issue_5085_2: {
|
issue_5085_2: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
@@ -3059,7 +3060,7 @@ issue_5085_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
var a = "PASS";
|
var a = "PASS";
|
||||||
(function(b) {
|
(function(b) {
|
||||||
b = [ 42 ][0];
|
0;
|
||||||
})();
|
})();
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
@@ -3400,7 +3401,7 @@ issue_5222: {
|
|||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_5288: {
|
issue_5288_1: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
@@ -3420,7 +3421,37 @@ issue_5288: {
|
|||||||
}() ]));
|
}() ]));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
while (console ? console.log("PASS") : 0, void 0);
|
while (function() {
|
||||||
|
if (console)
|
||||||
|
console.log("PASS");
|
||||||
|
}(), void 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5288_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (function([]) {}([ function f() {
|
||||||
|
if (console)
|
||||||
|
return console.log("PASS");
|
||||||
|
else {
|
||||||
|
let a = 0;
|
||||||
|
}
|
||||||
|
}() ]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (console && console.log("PASS"), void 0);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
@@ -3535,3 +3566,83 @@ issue_5405_2: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5423: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f({
|
||||||
|
[function() {
|
||||||
|
if (++a)
|
||||||
|
return 42;
|
||||||
|
}()]: c
|
||||||
|
}) {}
|
||||||
|
f(b = f);
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f({
|
||||||
|
[function() {
|
||||||
|
if (++a)
|
||||||
|
return 42;
|
||||||
|
}()]: c
|
||||||
|
}) {}
|
||||||
|
f(b = f);
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5454: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
var a = 42, a = {
|
||||||
|
p: [ a ] = [],
|
||||||
|
};
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = 42, a = {
|
||||||
|
p: [ a ] = [],
|
||||||
|
};
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5485: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f({
|
||||||
|
p: f,
|
||||||
|
[console.log(void 0 === f ? "PASS" : "FAIL")]: a,
|
||||||
|
}) {})(42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function f({
|
||||||
|
p: f,
|
||||||
|
[console.log(void 0 === f ? "PASS" : "FAIL")]: a,
|
||||||
|
}) {})(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -496,3 +496,16 @@ issue_4766: {
|
|||||||
export var a = "bar";
|
export var a = "bar";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5444: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
export var a = (console, console);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console;
|
||||||
|
export var a = console;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8398,3 +8398,251 @@ issue_5409: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_1: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
return f();
|
||||||
|
}() ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}() ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_1_strict: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function f() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_2: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_2_strict: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function f() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_3: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return f();
|
||||||
|
}() ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return f();
|
||||||
|
}() ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_3_strict: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function f() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_4: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return function() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mixed_mode_inline_4_strict: {
|
||||||
|
options = {
|
||||||
|
directives: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function f() {
|
||||||
|
"use strict";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
return f();
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}() ? "FAIL" : "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
module_inline: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
module: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = f;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(f() === a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = f;
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(a === a);
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1176,3 +1176,30 @@ issue_5182: {
|
|||||||
"42",
|
"42",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5441: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
(function() {
|
||||||
|
a = { p: this };
|
||||||
|
})();
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
(function() {
|
||||||
|
a_p = this;
|
||||||
|
})();
|
||||||
|
var a_p;
|
||||||
|
return typeof {};
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1604,48 +1604,6 @@ issue_4305_2: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1753: {
|
|
||||||
mangle = {
|
|
||||||
toplevel: false,
|
|
||||||
webkit: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
"use strict";
|
|
||||||
let l = null;
|
|
||||||
for (let i = 0; i < 1; i++)
|
|
||||||
console.log(i);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
"use strict";
|
|
||||||
let l = null;
|
|
||||||
for (let i = 0; i < 1; i++)
|
|
||||||
console.log(i);
|
|
||||||
}
|
|
||||||
expect_stdout: "0"
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1753_toplevel: {
|
|
||||||
mangle = {
|
|
||||||
toplevel: true,
|
|
||||||
webkit: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
"use strict";
|
|
||||||
let l = null;
|
|
||||||
for (let i = 0; i < 1; i++)
|
|
||||||
console.log(i);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
"use strict";
|
|
||||||
let l = null;
|
|
||||||
for (let e = 0; e < 1; e++)
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
expect_stdout: "0"
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_4438: {
|
issue_4438: {
|
||||||
options = {
|
options = {
|
||||||
if_return: true,
|
if_return: true,
|
||||||
@@ -2020,3 +1978,23 @@ issue_5338: {
|
|||||||
expect_stdout: ReferenceError("a is not defined")
|
expect_stdout: ReferenceError("a is not defined")
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5476: {
|
||||||
|
mangle = {
|
||||||
|
keep_fargs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(n) {
|
||||||
|
let a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(n) {
|
||||||
|
let o;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3702,3 +3702,146 @@ issue_5182: {
|
|||||||
]
|
]
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5420: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
a && a.p;
|
||||||
|
a = "FAIL 2";
|
||||||
|
try {
|
||||||
|
continue;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = "FAIL 3";
|
||||||
|
} while (console.log(b || "PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
a && a.p;
|
||||||
|
a = "FAIL 2";
|
||||||
|
try {
|
||||||
|
continue;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = "FAIL 3";
|
||||||
|
} while (console.log(b || "PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5451: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
A = 1;
|
||||||
|
var a = 1, b;
|
||||||
|
console.log(function f() {
|
||||||
|
return a-- && f(b = A, b);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
A = 1;
|
||||||
|
var a = 1, b;
|
||||||
|
console.log(function f() {
|
||||||
|
return a-- && f(b = A, b);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5471_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
function f(b, c) {
|
||||||
|
function g() {
|
||||||
|
if (console)
|
||||||
|
return 42;
|
||||||
|
else
|
||||||
|
c = "FAIL 2";
|
||||||
|
}
|
||||||
|
var d = g();
|
||||||
|
console.log(c || "PASS");
|
||||||
|
var e = function h() {
|
||||||
|
while (b && e);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
f(a++) && a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
var b, c, e;
|
||||||
|
b = +a,
|
||||||
|
function() {
|
||||||
|
if (console)
|
||||||
|
return;
|
||||||
|
c = "FAIL 2";
|
||||||
|
}(),
|
||||||
|
console.log(c || "PASS"),
|
||||||
|
e = function() {
|
||||||
|
while (b && e);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5471_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
function f(b, c) {
|
||||||
|
function g() {
|
||||||
|
if (console)
|
||||||
|
return 42;
|
||||||
|
else
|
||||||
|
c = "FAIL 2";
|
||||||
|
}
|
||||||
|
var d = g();
|
||||||
|
console.log(c || "PASS");
|
||||||
|
var e = function h() {
|
||||||
|
while (b && e);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
f(a++) && a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL 1";
|
||||||
|
var b, c, e;
|
||||||
|
b = +a,
|
||||||
|
function() {
|
||||||
|
if (console)
|
||||||
|
return;
|
||||||
|
c = "FAIL 2";
|
||||||
|
}(),
|
||||||
|
console.log(c || "PASS"),
|
||||||
|
e = function() {
|
||||||
|
while (b && e);
|
||||||
|
}(),
|
||||||
|
void 0;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -7861,3 +7861,38 @@ issue_5324: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5434: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
for (var i = 0; i < 2; i++) {
|
||||||
|
var b = "FAIL";
|
||||||
|
f && f();
|
||||||
|
a = b;
|
||||||
|
var f = function() {
|
||||||
|
b = "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
for (var i = 0; i < 2; i++) {
|
||||||
|
var b = "FAIL";
|
||||||
|
f && f();
|
||||||
|
a = b;
|
||||||
|
var f = function() {
|
||||||
|
b = "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ hoist_props_const: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var o = 0, o_p = "PASS";
|
var o, o_p = "PASS";
|
||||||
console.log(o_p);
|
console.log(o_p);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
|
|||||||
@@ -107,3 +107,209 @@ function_name_mangle_ie8: {
|
|||||||
expect_exact: "(function(){console.log(typeof function n(o){})})();"
|
expect_exact: "(function(){console.log(typeof function n(o){})})();"
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1753: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1753_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let e = 0; e < 1; e++)
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5032_await: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
webkit: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
async function f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
async function f(a) {
|
||||||
|
var a = log(a), c = a;
|
||||||
|
log(a);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5032_await_webkit: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
async function f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
async function f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=8"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5032_yield: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
webkit: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function *f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS").next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function *f(a) {
|
||||||
|
var a = log(a), c = a;
|
||||||
|
log(a);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS").next();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5032_yield_webkit: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function *f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS").next();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function log(value) {
|
||||||
|
console.log(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function *f(a) {
|
||||||
|
var b = log(a), c = b;
|
||||||
|
log(b);
|
||||||
|
log(c);
|
||||||
|
}
|
||||||
|
f("PASS").next();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5480: {
|
||||||
|
mangle = {
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
L: for (let a in console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
o: for (let o in console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -978,8 +978,8 @@ issue_4454_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f(a) {
|
function f(a) {
|
||||||
(function*(c = console.log(a)) {})();
|
(function*(c = console.log(a)) {})();
|
||||||
var a = 42..toString();
|
var b = 42..toString();
|
||||||
console.log(a);
|
console.log(b);
|
||||||
}
|
}
|
||||||
f("PASS");
|
f("PASS");
|
||||||
}
|
}
|
||||||
@@ -1267,80 +1267,6 @@ issue_5019_2: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_5032_normal: {
|
|
||||||
options = {
|
|
||||||
merge_vars: true,
|
|
||||||
webkit: false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function *f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS").next();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function *f(a) {
|
|
||||||
var a = log(a), c = a;
|
|
||||||
log(a);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS").next();
|
|
||||||
}
|
|
||||||
expect_stdout: [
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
]
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_5032_webkit: {
|
|
||||||
options = {
|
|
||||||
merge_vars: true,
|
|
||||||
webkit: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function *f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS").next();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function log(value) {
|
|
||||||
console.log(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function *f(a) {
|
|
||||||
var b = log(a), c = b;
|
|
||||||
log(b);
|
|
||||||
log(c);
|
|
||||||
}
|
|
||||||
f("PASS").next();
|
|
||||||
}
|
|
||||||
expect_stdout: [
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
"PASS",
|
|
||||||
]
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_5034: {
|
issue_5034: {
|
||||||
options = {
|
options = {
|
||||||
functions: true,
|
functions: true,
|
||||||
@@ -1525,3 +1451,67 @@ issue_5385_2: {
|
|||||||
]
|
]
|
||||||
node_version: ">=10"
|
node_version: ">=10"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5425: {
|
||||||
|
options = {
|
||||||
|
assignments: true,
|
||||||
|
ie: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
yields: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
var b = function* f() {}(a ? a = "PASS" : 42);
|
||||||
|
console.log(a, typeof f);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
(function* f() {})(a && (a = "PASS"));
|
||||||
|
console.log(a, typeof f);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5456: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = true;
|
||||||
|
(function() {
|
||||||
|
(function(b, c) {
|
||||||
|
var d = function*() {
|
||||||
|
c = null;
|
||||||
|
}();
|
||||||
|
var e = function() {
|
||||||
|
if (c)
|
||||||
|
console.log(typeof d);
|
||||||
|
while (b);
|
||||||
|
}();
|
||||||
|
})(function(i) {
|
||||||
|
return console.log("foo") && i;
|
||||||
|
}(a));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = true;
|
||||||
|
(function() {
|
||||||
|
b = (i = a, console.log("foo") && i),
|
||||||
|
d = function*() {
|
||||||
|
c = null;
|
||||||
|
}(),
|
||||||
|
e = function() {
|
||||||
|
if (c) console.log(typeof d);
|
||||||
|
while (b);
|
||||||
|
}(),
|
||||||
|
void 0;
|
||||||
|
var b, c, d, e;
|
||||||
|
var i;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "foo"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
1
test/input/module/expect.js
Normal file
1
test/input/module/expect.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
function n(){return this||arguments[0]+arguments[1]}function o(){return this||arguments[0]+arguments[1]}console.log(n(n(1,3),5)),console.log(o(o(2,4),6));
|
||||||
13
test/input/module/input.js
Normal file
13
test/input/module/input.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
console.log(function() {
|
||||||
|
function sum(...params) {
|
||||||
|
return this || arguments[0] + arguments[1];
|
||||||
|
}
|
||||||
|
return sum(sum(1, 3), 5);
|
||||||
|
}());
|
||||||
|
console.log(function() {
|
||||||
|
"use strict";
|
||||||
|
function sum(...params) {
|
||||||
|
return this || arguments[0] + arguments[1];
|
||||||
|
}
|
||||||
|
return sum(sum(2, 4), 6);
|
||||||
|
}());
|
||||||
@@ -928,6 +928,14 @@ describe("bin/uglifyjs", function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should work with --module", function(done) {
|
||||||
|
var command = uglifyjscmd + " test/input/module/input.js --module -mc";
|
||||||
|
exec(command, function(err, stdout, stderr) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(stdout, read("test/input/module/expect.js"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should compress swarm of unused variables with reasonable performance", function(done) {
|
it("Should compress swarm of unused variables with reasonable performance", function(done) {
|
||||||
var code = [
|
var code = [
|
||||||
"console.log(function() {",
|
"console.log(function() {",
|
||||||
|
|||||||
@@ -210,10 +210,10 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
if (node.expression instanceof U.AST_Function) {
|
if (node.expression instanceof U.AST_Function) {
|
||||||
// hoist and return expressions from the IIFE function expression
|
// hoist and return expressions from the IIFE function expression
|
||||||
var seq = [];
|
var scope = tt.find_parent(U.AST_Scope), seq = [];
|
||||||
node.expression.body.forEach(function(node) {
|
node.expression.body.forEach(function(node) {
|
||||||
var expr = node instanceof U.AST_Exit ? node.value : node.body;
|
var expr = node instanceof U.AST_Exit ? node.value : node.body;
|
||||||
if (expr instanceof U.AST_Node && !U.is_statement(expr) && can_hoist(expr)) {
|
if (expr instanceof U.AST_Node && !U.is_statement(expr) && can_hoist(expr, scope)) {
|
||||||
// collect expressions from each statement's body
|
// collect expressions from each statement's body
|
||||||
seq.push(expr);
|
seq.push(expr);
|
||||||
}
|
}
|
||||||
@@ -264,11 +264,12 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.skip;
|
return List.skip;
|
||||||
default:
|
default:
|
||||||
if (!has_exit(node) && can_hoist(node)) {
|
if (can_hoist(node, tt.find_parent(U.AST_Scope))) {
|
||||||
// hoist function declaration body
|
// hoist function declaration body
|
||||||
var body = node.body;
|
var body = node.body;
|
||||||
node.body = [];
|
node.body = [];
|
||||||
body.push(node); // retain function with empty body to be dropped later
|
// retain function with empty body to be dropped later
|
||||||
|
body.push(node);
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.splice(body);
|
return List.splice(body);
|
||||||
}
|
}
|
||||||
@@ -382,7 +383,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
|
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
|
||||||
// hoist simple statement IIFE function expression body
|
// hoist simple statement IIFE function expression body
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
if (!has_exit(node.body.expression) && can_hoist(node.body.expression)) {
|
if (can_hoist(node.body.expression, tt.find_parent(U.AST_Scope))) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.splice(node.body.expression.body);
|
return List.splice(node.body.expression.body);
|
||||||
}
|
}
|
||||||
@@ -647,21 +648,6 @@ function trim_trailing_whitespace(value) {
|
|||||||
return ("" + value).replace(/\s+$/, "");
|
return ("" + value).replace(/\s+$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function has_exit(fn) {
|
|
||||||
var found = false;
|
|
||||||
var tw = new U.TreeWalker(function(node) {
|
|
||||||
if (found) return found;
|
|
||||||
if (node instanceof U.AST_Exit) {
|
|
||||||
return found = true;
|
|
||||||
}
|
|
||||||
if (node instanceof U.AST_Scope && node !== fn) {
|
|
||||||
return true; // don't descend into nested functions
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fn.walk(tw);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
function has_loopcontrol(body, loop, label) {
|
function has_loopcontrol(body, loop, label) {
|
||||||
var found = false;
|
var found = false;
|
||||||
var tw = new U.TreeWalker(function(node) {
|
var tw = new U.TreeWalker(function(node) {
|
||||||
@@ -676,17 +662,31 @@ function has_loopcontrol(body, loop, label) {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
function can_hoist(body) {
|
function can_hoist(body, scope) {
|
||||||
var found = false;
|
var found = false;
|
||||||
body.walk(new U.TreeWalker(function(node) {
|
var tw = new U.TreeWalker(function(node) {
|
||||||
if (found) return true;
|
if (found) return true;
|
||||||
|
if (node instanceof U.AST_Exit) return found = true;
|
||||||
if (node instanceof U.AST_NewTarget) return found = true;
|
if (node instanceof U.AST_NewTarget) return found = true;
|
||||||
if (node instanceof U.AST_Scope) {
|
if (node instanceof U.AST_Scope) {
|
||||||
if (node === body) return;
|
if (node === body) return;
|
||||||
|
if (node instanceof U.AST_Arrow || node instanceof U.AST_AsyncArrow) node.argnames.forEach(function(sym) {
|
||||||
|
sym.walk(tw);
|
||||||
|
});
|
||||||
|
// don't descend into nested functions
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof U.AST_Super) return found = true;
|
if (node instanceof U.AST_Super) return found = true;
|
||||||
}));
|
if (node instanceof U.AST_SymbolDeclaration || node instanceof U.AST_SymbolRef) switch (node.name) {
|
||||||
|
case "await":
|
||||||
|
if (/^Async/.test(scope.TYPE)) return found = true;
|
||||||
|
return;
|
||||||
|
case "yield":
|
||||||
|
if (/Generator/.test(scope.TYPE)) return found = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
body.walk(tw);
|
||||||
return !found;
|
return !found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
|
|||||||
minify_in_situ "src" \
|
minify_in_situ "src" \
|
||||||
&& minify_in_situ "third_party" \
|
&& minify_in_situ "third_party" \
|
||||||
&& rm -rf node_modules \
|
&& rm -rf node_modules \
|
||||||
&& npm_install \
|
&& npm_install --package-lock \
|
||||||
&& rm -rf build/* \
|
&& rm -rf build/* \
|
||||||
&& npm run build:terser-bundled \
|
&& npm run build:terser-bundled \
|
||||||
&& npm run build:uglify-js-bundled \
|
&& npm run build:uglify-js-bundled \
|
||||||
|
|||||||
@@ -52,8 +52,11 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
|
|||||||
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
||||||
};
|
};
|
||||||
exports.patch_module_statements = function(code) {
|
exports.patch_module_statements = function(code) {
|
||||||
var count = 0, has_default = "", imports = [];
|
var count = 0, has_default = "", imports = [], strict_mode = "";
|
||||||
code = code.replace(/\bexport(?:\s*\{[^{}]*}\s*?(?:$|\n|;)|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
|
code = code.replace(/^\s*("|')use strict\1\s*;?/, function(match) {
|
||||||
|
strict_mode = match;
|
||||||
|
return "";
|
||||||
|
}).replace(/\bexport(?:\s*\{[^{}]*}\s*?(?:$|\n|;)|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
|
||||||
if (/^export\s+default/.test(match)) has_default = "var _uglify_export_default_;";
|
if (/^export\s+default/.test(match)) has_default = "var _uglify_export_default_;";
|
||||||
if (!header) return "";
|
if (!header) return "";
|
||||||
if (header.length == 1) return "0, " + header;
|
if (header.length == 1) return "0, " + header;
|
||||||
@@ -78,7 +81,7 @@ exports.patch_module_statements = function(code) {
|
|||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
imports.push("");
|
imports.push("");
|
||||||
return has_default + imports.join("\n") + code;
|
return strict_mode + has_default + imports.join("\n") + code;
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_error(result) {
|
function is_error(result) {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
|
|
||||||
var SUPPORT = function(matrix) {
|
var SUPPORT = function(matrix) {
|
||||||
for (var name in matrix) {
|
for (var name in matrix) {
|
||||||
matrix[name] = typeof sandbox.run_code(matrix[name]) == "string";
|
matrix[name] = !sandbox.is_error(sandbox.run_code(matrix[name]));
|
||||||
}
|
}
|
||||||
return matrix;
|
return matrix;
|
||||||
}({
|
}({
|
||||||
@@ -1805,7 +1805,7 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
|
|||||||
if (canThrow && rng(20) == 0) {
|
if (canThrow && rng(20) == 0) {
|
||||||
s += p;
|
s += p;
|
||||||
} else {
|
} else {
|
||||||
s += "(" + p + " && " + p + ".constructor === Function ? " + p + " : function() {})";
|
s += "(typeof " + p + ' == "function" && typeof ' + p + '.prototype == "object" && ' + p + ".constructor === Function ? " + p + " : function() {})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += " {\n";
|
s += " {\n";
|
||||||
@@ -1824,9 +1824,15 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
|
|||||||
declared.push(internal);
|
declared.push(internal);
|
||||||
}
|
}
|
||||||
if (SUPPORT.class_field && rng(2)) {
|
if (SUPPORT.class_field && rng(2)) {
|
||||||
s += internal || createObjectKey(recurmax, stmtDepth, canThrow);
|
if (internal) {
|
||||||
|
s += internal;
|
||||||
|
} else if (fixed && bug_class_static_nontrivial) {
|
||||||
|
s += getDotKey();
|
||||||
|
} else {
|
||||||
|
s += createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
}
|
||||||
if (rng(5)) {
|
if (rng(5)) {
|
||||||
async = bug_async_class_await && fixed && 0;
|
async = false;
|
||||||
generator = false;
|
generator = false;
|
||||||
s += " = " + createExpression(recurmax, NO_COMMA, stmtDepth, fixed ? canThrow : CANNOT_THROW);
|
s += " = " + createExpression(recurmax, NO_COMMA, stmtDepth, fixed ? canThrow : CANNOT_THROW);
|
||||||
generator = save_generator;
|
generator = save_generator;
|
||||||
@@ -2031,7 +2037,7 @@ function isBannedKeyword(name) {
|
|||||||
case "let":
|
case "let":
|
||||||
return in_class;
|
return in_class;
|
||||||
case "await":
|
case "await":
|
||||||
return async !== false;
|
return async || in_class && bug_class_static_await;
|
||||||
case "yield":
|
case "yield":
|
||||||
return generator || in_class;
|
return generator || in_class;
|
||||||
}
|
}
|
||||||
@@ -2110,7 +2116,7 @@ function try_beautify(code, toplevel, result, printfn, options) {
|
|||||||
} else if (options) {
|
} else if (options) {
|
||||||
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
var uglified = UglifyJS.minify(beautified.code, JSON.parse(options));
|
||||||
var expected, actual;
|
var expected, actual;
|
||||||
if (typeof uglify_code != "string" || uglified.error) {
|
if (sandbox.is_error(uglify_code) || uglified.error) {
|
||||||
expected = uglify_code;
|
expected = uglify_code;
|
||||||
actual = uglified.error;
|
actual = uglified.error;
|
||||||
} else {
|
} else {
|
||||||
@@ -2147,7 +2153,7 @@ function log_suspects(minify_options, component) {
|
|||||||
m[component] = o;
|
m[component] = o;
|
||||||
m.validate = true;
|
m.validate = true;
|
||||||
var result = UglifyJS.minify(original_code, m);
|
var result = UglifyJS.minify(original_code, m);
|
||||||
if (typeof uglify_code != "string") {
|
if (sandbox.is_error(uglify_code)) {
|
||||||
return !sandbox.same_stdout(uglify_code, result.error);
|
return !sandbox.same_stdout(uglify_code, result.error);
|
||||||
} else if (result.error) {
|
} else if (result.error) {
|
||||||
errorln("Error testing options." + component + "." + name);
|
errorln("Error testing options." + component + "." + name);
|
||||||
@@ -2175,7 +2181,7 @@ function log_suspects_global(options, toplevel) {
|
|||||||
m[component] = false;
|
m[component] = false;
|
||||||
m.validate = true;
|
m.validate = true;
|
||||||
var result = UglifyJS.minify(original_code, m);
|
var result = UglifyJS.minify(original_code, m);
|
||||||
if (typeof uglify_code != "string") {
|
if (sandbox.is_error(uglify_code)) {
|
||||||
return !sandbox.same_stdout(uglify_code, result.error);
|
return !sandbox.same_stdout(uglify_code, result.error);
|
||||||
} else if (result.error) {
|
} else if (result.error) {
|
||||||
errorln("Error testing options." + component);
|
errorln("Error testing options." + component);
|
||||||
@@ -2204,7 +2210,16 @@ function log(options) {
|
|||||||
errorln();
|
errorln();
|
||||||
errorln();
|
errorln();
|
||||||
errorln("//-------------------------------------------------------------");
|
errorln("//-------------------------------------------------------------");
|
||||||
if (typeof uglify_code == "string") {
|
if (sandbox.is_error(uglify_code)) {
|
||||||
|
errorln("// !!! uglify failed !!!");
|
||||||
|
errorln(uglify_code);
|
||||||
|
if (original_erred) {
|
||||||
|
errorln();
|
||||||
|
errorln();
|
||||||
|
errorln("original stacktrace:");
|
||||||
|
errorln(original_result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
errorln("// uglified code");
|
errorln("// uglified code");
|
||||||
try_beautify(uglify_code, toplevel, uglify_result, errorln);
|
try_beautify(uglify_code, toplevel, uglify_result, errorln);
|
||||||
errorln();
|
errorln();
|
||||||
@@ -2213,15 +2228,6 @@ function log(options) {
|
|||||||
errorln(original_result);
|
errorln(original_result);
|
||||||
errorln("uglified result:");
|
errorln("uglified result:");
|
||||||
errorln(uglify_result);
|
errorln(uglify_result);
|
||||||
} else {
|
|
||||||
errorln("// !!! uglify failed !!!");
|
|
||||||
errorln(uglify_code);
|
|
||||||
if (errored) {
|
|
||||||
errorln();
|
|
||||||
errorln();
|
|
||||||
errorln("original stacktrace:");
|
|
||||||
errorln(original_result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
errorln("//-------------------------------------------------------------");
|
errorln("//-------------------------------------------------------------");
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -2318,20 +2324,28 @@ function is_error_in(ex) {
|
|||||||
return ex.name == "TypeError" && /'in'/.test(ex.message);
|
return ex.name == "TypeError" && /'in'/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_error_tdz(ex) {
|
||||||
|
return ex.name == "ReferenceError";
|
||||||
|
}
|
||||||
|
|
||||||
function is_error_spread(ex) {
|
function is_error_spread(ex) {
|
||||||
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function/.test(ex.message);
|
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function|Symbol\(Symbol\.iterator\)/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_error_recursion(ex) {
|
function is_error_recursion(ex) {
|
||||||
return ex.name == "RangeError" && /Invalid string length|Maximum call stack size exceeded/.test(ex.message);
|
return ex.name == "RangeError" && /Invalid string length|Maximum call stack size exceeded/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_error_set_property(ex) {
|
||||||
|
return ex.name == "TypeError" && /^Cannot set propert[\s\S]+? of (null|undefined)/.test(ex.message);
|
||||||
|
}
|
||||||
|
|
||||||
function is_error_redeclaration(ex) {
|
function is_error_redeclaration(ex) {
|
||||||
return ex.name == "SyntaxError" && /already been declared|redeclaration/.test(ex.message);
|
return ex.name == "SyntaxError" && /already been declared|redeclaration/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_error_destructuring(ex) {
|
function is_error_destructuring(ex) {
|
||||||
return ex.name == "TypeError" && /^Cannot destructure /.test(ex.message);
|
return ex.name == "TypeError" && /^Cannot (destructure|read propert)/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_error_class_constructor(ex) {
|
function is_error_class_constructor(ex) {
|
||||||
@@ -2345,6 +2359,8 @@ function is_error_getter_only_property(ex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function patch_try_catch(orig, toplevel) {
|
function patch_try_catch(orig, toplevel) {
|
||||||
|
var patched = Object.create(null);
|
||||||
|
var patches = [];
|
||||||
var stack = [ {
|
var stack = [ {
|
||||||
code: orig,
|
code: orig,
|
||||||
index: 0,
|
index: 0,
|
||||||
@@ -2382,7 +2398,7 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
"throw " + match[1] + ";",
|
"throw " + match[1] + ";",
|
||||||
].join("\n");
|
].join("\n");
|
||||||
}
|
}
|
||||||
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw;
|
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw + "var UFUZZ_ERROR;";
|
||||||
var result = run_code(new_code, toplevel);
|
var result = run_code(new_code, toplevel);
|
||||||
if (!sandbox.is_error(result)) {
|
if (!sandbox.is_error(result)) {
|
||||||
if (!stack.filled && match[1]) stack.push({
|
if (!stack.filled && match[1]) stack.push({
|
||||||
@@ -2394,27 +2410,35 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
offset += insert.length;
|
offset += insert.length;
|
||||||
code = new_code;
|
code = new_code;
|
||||||
} else if (is_error_in(result)) {
|
} else if (is_error_in(result)) {
|
||||||
index = result.ufuzz_catch;
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("invalid `in`");');
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
} else if (is_error_tdz(result)) {
|
||||||
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("TDZ");');
|
||||||
} else if (is_error_spread(result)) {
|
} else if (is_error_spread(result)) {
|
||||||
index = result.ufuzz_catch;
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("spread not iterable");');
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("spread not iterable");' + orig.slice(index);
|
|
||||||
} else if (is_error_recursion(result)) {
|
} else if (is_error_recursion(result)) {
|
||||||
index = result.ufuzz_try;
|
patch(result.ufuzz_try, 'throw new Error("skipping infinite recursion");');
|
||||||
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
} else if (is_error_set_property(result)) {
|
||||||
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("cannot set property");');
|
||||||
} else if (is_error_destructuring(result)) {
|
} else if (is_error_destructuring(result)) {
|
||||||
index = result.ufuzz_catch;
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("cannot destructure");');
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("cannot destructure");' + orig.slice(index);
|
|
||||||
} else if (is_error_class_constructor(result)) {
|
} else if (is_error_class_constructor(result)) {
|
||||||
index = result.ufuzz_catch;
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("missing new for class");');
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("missing new for class");' + orig.slice(index);
|
|
||||||
} else if (is_error_getter_only_property(result)) {
|
} else if (is_error_getter_only_property(result)) {
|
||||||
index = result.ufuzz_catch;
|
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("setting getter-only property");');
|
||||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("setting getter-only property");' + orig.slice(index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.filled = true;
|
stack.filled = true;
|
||||||
}
|
}
|
||||||
|
if (patches.length) return patches.reduce(function(code, patch) {
|
||||||
|
var index = patch[0];
|
||||||
|
return code.slice(0, index) + patch[1] + code.slice(index);
|
||||||
|
}, orig);
|
||||||
|
|
||||||
|
function patch(index, code) {
|
||||||
|
if (patched[index]) return;
|
||||||
|
patched[index] = true;
|
||||||
|
patches.unshift([ index, code ]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var beautify_options = {
|
var beautify_options = {
|
||||||
@@ -2426,22 +2450,23 @@ var beautify_options = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
var minify_options = require("./options.json");
|
var minify_options = require("./options.json");
|
||||||
if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") {
|
if (sandbox.is_error(sandbox.run_code("A:if (0) B:; else B:;"))) {
|
||||||
minify_options.forEach(function(o) {
|
minify_options.forEach(function(o) {
|
||||||
if (!("mangle" in o)) o.mangle = {};
|
if (!("mangle" in o)) o.mangle = {};
|
||||||
if (o.mangle) o.mangle.v8 = true;
|
if (o.mangle) o.mangle.v8 = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var bug_async_arrow_rest = function() {};
|
var bug_async_arrow_rest = function() {};
|
||||||
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && typeof sandbox.run_code("async (a = f(...[], b)) => 0;") != "string") {
|
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && sandbox.is_error(sandbox.run_code("async (a = f(...[], b)) => 0;"))) {
|
||||||
bug_async_arrow_rest = function(ex) {
|
bug_async_arrow_rest = function(ex) {
|
||||||
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
|
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var bug_async_class_await = SUPPORT.async && SUPPORT.class_field && typeof sandbox.run_code("var await; async function f() { class A { static p = await; } }") != "string";
|
var bug_class_static_await = SUPPORT.async && SUPPORT.class_field && sandbox.is_error(sandbox.run_code("var await; class A { static p = await; }"));
|
||||||
var bug_for_of_async = SUPPORT.for_await_of && typeof sandbox.run_code("var async; for (async of []);") != "string";
|
var bug_class_static_nontrivial = SUPPORT.class_field && sandbox.is_error(sandbox.run_code("class A { static 42; static get 42() {} }"));
|
||||||
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && typeof sandbox.run_code("try {} catch (e) { for (var e of []); }") != "string";
|
var bug_for_of_async = SUPPORT.for_await_of && sandbox.is_error(sandbox.run_code("var async; for (async of []);"));
|
||||||
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && sandbox.is_error(sandbox.run_code("try {} catch (e) { for (var e of []); }"));
|
||||||
|
if (SUPPORT.destructuring && sandbox.is_error(sandbox.run_code("console.log([ 1 ], {} = 2);"))) {
|
||||||
beautify_options.output.v8 = true;
|
beautify_options.output.v8 = true;
|
||||||
minify_options.forEach(function(o) {
|
minify_options.forEach(function(o) {
|
||||||
if (!("output" in o)) o.output = {};
|
if (!("output" in o)) o.output = {};
|
||||||
@@ -2450,7 +2475,7 @@ if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2)
|
|||||||
}
|
}
|
||||||
beautify_options = JSON.stringify(beautify_options);
|
beautify_options = JSON.stringify(beautify_options);
|
||||||
minify_options = minify_options.map(JSON.stringify);
|
minify_options = minify_options.map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, original_erred;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
for (var round = 1; round <= num_iterations; round++) {
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
@@ -2458,7 +2483,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
original_code = createTopLevelCode();
|
original_code = createTopLevelCode();
|
||||||
var orig_result = [ run_code(original_code), run_code(original_code, true) ];
|
var orig_result = [ run_code(original_code), run_code(original_code, true) ];
|
||||||
if (orig_result.some(function(result, toplevel) {
|
if (orig_result.some(function(result, toplevel) {
|
||||||
if (typeof result == "string") return;
|
if (!sandbox.is_error(result)) return;
|
||||||
println();
|
println();
|
||||||
println();
|
println();
|
||||||
println("//=============================================================");
|
println("//=============================================================");
|
||||||
@@ -2480,19 +2505,20 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
o.validate = true;
|
o.validate = true;
|
||||||
uglify_code = UglifyJS.minify(original_code, o);
|
uglify_code = UglifyJS.minify(original_code, o);
|
||||||
original_result = orig_result[toplevel ? 1 : 0];
|
original_result = orig_result[toplevel ? 1 : 0];
|
||||||
errored = typeof original_result != "string";
|
original_erred = sandbox.is_error(original_result);
|
||||||
if (!uglify_code.error) {
|
if (!uglify_code.error) {
|
||||||
uglify_code = uglify_code.code;
|
uglify_code = uglify_code.code;
|
||||||
uglify_result = run_code(uglify_code, toplevel);
|
uglify_result = run_code(uglify_code, toplevel);
|
||||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||||
|
var uglify_erred = sandbox.is_error(uglify_result);
|
||||||
// ignore v8 parser bug
|
// ignore v8 parser bug
|
||||||
if (!ok && bug_async_arrow_rest(uglify_result)) ok = true;
|
if (!ok && uglify_erred && bug_async_arrow_rest(uglify_result)) ok = true;
|
||||||
// ignore runtime platform bugs
|
// ignore runtime platform bugs
|
||||||
if (!ok && uglify_result.message == "Script execution aborted.") ok = true;
|
if (!ok && uglify_erred && uglify_result.message == "Script execution aborted.") ok = true;
|
||||||
// handle difference caused by time-outs
|
// handle difference caused by time-outs
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
if (errored && is_error_timeout(original_result)) {
|
if (original_erred && is_error_timeout(original_result)) {
|
||||||
if (is_error_timeout(uglify_result)) {
|
if (uglify_erred && is_error_timeout(uglify_result)) {
|
||||||
// ignore difference in error message
|
// ignore difference in error message
|
||||||
ok = true;
|
ok = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -2500,21 +2526,23 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = run_code(original_code, toplevel, 10000);
|
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = run_code(original_code, toplevel, 10000);
|
||||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||||
}
|
}
|
||||||
} else if (is_error_timeout(uglify_result)) {
|
} else if (uglify_erred && is_error_timeout(uglify_result)) {
|
||||||
// ignore spurious time-outs
|
// ignore spurious time-outs
|
||||||
var waited_result = run_code(uglify_code, toplevel, 10000);
|
var waited_result = run_code(uglify_code, toplevel, 10000);
|
||||||
ok = sandbox.same_stdout(original_result, waited_result);
|
ok = sandbox.same_stdout(original_result, waited_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ignore declaration order of global variables
|
// ignore declaration order of global variables
|
||||||
if (!ok && !toplevel && uglify_result.name != "SyntaxError" && original_result.name != "SyntaxError") {
|
if (!ok && !toplevel) {
|
||||||
ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
|
if (!(original_erred && original_result.name == "SyntaxError") && !(uglify_erred && uglify_result.name == "SyntaxError")) {
|
||||||
|
ok = sandbox.same_stdout(run_code(sort_globals(original_code)), run_code(sort_globals(uglify_code)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ignore numerical imprecision caused by `unsafe_math`
|
// ignore numerical imprecision caused by `unsafe_math`
|
||||||
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == typeof uglify_result) {
|
if (!ok && o.compress && o.compress.unsafe_math) {
|
||||||
if (typeof original_result == "string") {
|
if (typeof original_result == "string" && typeof uglify_result == "string") {
|
||||||
ok = fuzzy_match(original_result, uglify_result);
|
ok = fuzzy_match(original_result, uglify_result);
|
||||||
} else if (sandbox.is_error(original_result)) {
|
} else if (original_erred && uglify_erred) {
|
||||||
ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message);
|
ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message);
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -2522,46 +2550,33 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ignore difference in error message caused by Temporal Dead Zone
|
if (!ok && original_erred && uglify_erred && (
|
||||||
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
// ignore difference in error message caused by `in`
|
||||||
// ignore difference due to implicit strict-mode in `class`
|
is_error_in(original_result) && is_error_in(uglify_result)
|
||||||
if (!ok && /\bclass\b/.test(original_code)) {
|
// ignore difference in error message caused by Temporal Dead Zone
|
||||||
var original_strict = run_code('"use strict";\n' + original_code, toplevel);
|
|| is_error_tdz(original_result) && is_error_tdz(uglify_result)
|
||||||
if (/^(Syntax|Type)Error$/.test(uglify_result.name)) {
|
// ignore difference in error message caused by spread syntax
|
||||||
ok = typeof original_strict != "string";
|
|| is_error_spread(original_result) && is_error_spread(uglify_result)
|
||||||
} else {
|
// ignore difference in error message caused by destructuring assignment
|
||||||
ok = sandbox.same_stdout(original_strict, uglify_result);
|
|| is_error_set_property(original_result) && is_error_set_property(uglify_result)
|
||||||
}
|
// ignore difference in error message caused by `import` symbol redeclaration
|
||||||
}
|
|| /\bimport\b/.test(original_code) && is_error_redeclaration(original_result) && is_error_redeclaration(uglify_result)
|
||||||
// ignore difference in error message caused by `import` symbol redeclaration
|
// ignore difference in error message caused by destructuring
|
||||||
if (!ok && errored && /\bimport\b/.test(original_code)) {
|
|| is_error_destructuring(original_result) && is_error_destructuring(uglify_result)
|
||||||
if (is_error_redeclaration(uglify_result) && is_error_redeclaration(original_result)) ok = true;
|
// ignore difference in error message caused by call on class
|
||||||
}
|
|| is_error_class_constructor(original_result) && is_error_class_constructor(uglify_result)
|
||||||
|
// ignore difference in error message caused by setting getter-only property
|
||||||
|
|| is_error_getter_only_property(original_result) && is_error_getter_only_property(uglify_result)
|
||||||
|
)) ok = true;
|
||||||
// ignore difference due to `__proto__` assignment
|
// ignore difference due to `__proto__` assignment
|
||||||
if (!ok && /\b__proto__\b/.test(original_code)) {
|
if (!ok && /\b__proto__\b/.test(original_code)) {
|
||||||
var original_proto = run_code("(" + patch_proto + ")();\n" + original_code, toplevel);
|
var original_proto = run_code("(" + patch_proto + ")();\n" + original_code, toplevel);
|
||||||
var uglify_proto = run_code("(" + patch_proto + ")();\n" + uglify_code, toplevel);
|
var uglify_proto = run_code("(" + patch_proto + ")();\n" + uglify_code, toplevel);
|
||||||
ok = sandbox.same_stdout(original_proto, uglify_proto);
|
ok = sandbox.same_stdout(original_proto, uglify_proto);
|
||||||
}
|
}
|
||||||
// ignore difference in error message caused by `in`
|
|
||||||
if (!ok && errored && is_error_in(uglify_result) && is_error_in(original_result)) ok = true;
|
|
||||||
// ignore difference in error message caused by spread syntax
|
|
||||||
if (!ok && errored && is_error_spread(uglify_result) && is_error_spread(original_result)) ok = true;
|
|
||||||
// ignore difference in depth of termination caused by infinite recursion
|
// ignore difference in depth of termination caused by infinite recursion
|
||||||
if (!ok && errored && is_error_recursion(original_result)) {
|
if (!ok && original_erred && is_error_recursion(original_result)) {
|
||||||
if (is_error_recursion(uglify_result) || typeof uglify_result == "string") ok = true;
|
if (!uglify_erred || is_error_recursion(uglify_result)) ok = true;
|
||||||
}
|
|
||||||
// ignore difference in error message caused by destructuring
|
|
||||||
if (!ok && errored && is_error_destructuring(uglify_result) && is_error_destructuring(original_result)) {
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
// ignore difference in error message caused by call on class
|
|
||||||
if (!ok && errored && is_error_class_constructor(uglify_result) && is_error_class_constructor(original_result)) {
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
// ignore difference in error message caused by setting getter-only property
|
|
||||||
if (!ok && errored && is_error_getter_only_property(uglify_result) && is_error_getter_only_property(original_result)) {
|
|
||||||
ok = true;
|
|
||||||
}
|
}
|
||||||
// ignore errors above when caught by try-catch
|
// ignore errors above when caught by try-catch
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -2573,7 +2588,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uglify_code = uglify_code.error;
|
uglify_code = uglify_code.error;
|
||||||
ok = errored && uglify_code.name == original_result.name;
|
ok = original_erred && uglify_code.name == original_result.name;
|
||||||
}
|
}
|
||||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||||
if (!ok && isFinite(num_iterations)) {
|
if (!ok && isFinite(num_iterations)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user