Compare commits

..

66 Commits

Author SHA1 Message Date
Alex Lam S.L
2c5e23506b v3.14.5 2021-12-13 08:11:48 +08:00
Alex Lam S.L
07f35ea2c9 suppress false positives in ufuzz (#5216)
closes #5212
closes #5215
2021-12-12 06:19:06 +08:00
Alex Lam S.L
57a9519c3d fix corner case in objects (#5214)
fixes #5213
2021-12-10 06:02:22 +08:00
Alex Lam S.L
9e4c4c995c minor clean-up (#5210) 2021-12-10 04:48:06 +08:00
Alex Lam S.L
d11c82f8ca minor clean-up (#5209) 2021-12-09 05:14:57 +08:00
Alex Lam S.L
bc27966a19 workaround v8 performance quirks (#5207) 2021-12-08 13:40:47 +08:00
Alex Lam S.L
8f39491e96 workaround Unicode compatibility in testing (#5206) 2021-12-07 18:56:57 +08:00
Alex Lam S.L
065c50ebde improve sandbox resilience against process aborts (#5205) 2021-12-07 04:54:58 +08:00
Alex Lam S.L
d2e7c4af20 improve testing compatibility with Node.js (#5204) 2021-12-06 22:42:45 +08:00
Alex Lam S.L
033d8d9405 reduce memory pressure via bit fields (#5203) 2021-12-06 11:30:05 +08:00
Alex Lam S.L
b0799105c2 improve Dictionary performance (#5202)
- workaround `__proto__` quirks on v8
2021-12-05 14:58:52 +08:00
Alex Lam S.L
860aa9531b v3.14.4 2021-12-01 02:34:20 +08:00
Alex Lam S.L
2547542873 workaround sporadic slowdown in GitHub Actions (#5201) 2021-11-28 08:45:29 +08:00
Alex Lam S.L
3f8f0e246e fix corner case in collapse_vars (#5200)
fixes #5199
2021-11-28 01:43:43 +08:00
Alex Lam S.L
12227ebbb0 workaround toString() quirks on global context (#5198)
closes #5197
2021-11-27 23:17:51 +08:00
Alex Lam S.L
1b4bd7082b fix corner case in hoist_vars (#5196)
fixes #5195
2021-11-25 04:49:38 +08:00
Alex Lam S.L
0b6c185818 enhance merge_vars (#5194)
closes #5182
2021-11-24 19:08:40 +08:00
Alex Lam S.L
bfd0ac7f4b fix corner case in ie (#5193)
fixes #5192
2021-11-24 17:29:26 +08:00
Alex Lam S.L
1a8f2ecc65 enhance collapse_vars (#5186)
closes #5182
2021-11-24 17:28:36 +08:00
Alex Lam S.L
dc9e1ff0b1 fix corner case in unused (#5190)
fixes #5189
2021-11-23 20:10:05 +08:00
Alex Lam S.L
ea10498902 fix corner case in hoist_vars (#5188)
fixes #5187
2021-11-23 18:00:47 +08:00
Alex Lam S.L
69636dad69 improve sandbox async detection (#5185)
closes #5184
2021-11-23 02:29:54 +08:00
Alex Lam S.L
3ee1b0d00d enhance hoist_props & reduce_vars (#5183)
closes #5182
2021-11-23 00:31:10 +08:00
Alex Lam S.L
1e3ca4c6f7 enhance side_effects & unused (#5181) 2021-11-22 11:14:28 +08:00
Alex Lam S.L
839f4361f4 minor clean-up (#5180) 2021-11-19 16:34:11 +08:00
Alex Lam S.L
ae5c3ee8a1 fix corner cases in properties (#5178)
fixes #5177
2021-11-17 04:21:44 +08:00
Alex Lam S.L
77f7ae5ba2 fix corner case in join_vars (#5176)
fixes #5175
2021-11-15 21:35:54 +08:00
Alex Lam S.L
2d0f8bcff5 fix corner case in inline (#5174)
fixes #5173
2021-11-15 07:14:08 +08:00
Alex Lam S.L
f97e107c09 enhance reduce_vars (#5171) 2021-11-13 22:18:56 +08:00
Alex Lam S.L
e9932e1314 fix corner case in collapse_vars (#5169)
fixes #5168
2021-11-13 22:18:18 +08:00
Alex Lam S.L
eaa84d32df include Node.js v16 in CI tests (#5170)
- fix compatibility issues on v0.10 & v0.12
2021-11-13 18:34:18 +08:00
Alex Lam S.L
6e4aa0326f enhance reduce_vars (#5164)
- fix corner case in `join_vars`
2021-11-04 18:36:39 +08:00
Alex Lam S.L
f9a4b36dd1 fix corner cases in reduce_vars & rests (#5166)
fixes #5165
2021-11-03 21:29:01 +08:00
Alex Lam S.L
3acb5a329e enhance join_vars (#5162) 2021-11-02 11:33:24 +08:00
Alex Lam S.L
6d94242318 enhance reduce_vars (#5163) 2021-11-02 11:32:26 +08:00
Alex Lam S.L
bca83cb9df v3.14.3 2021-11-02 05:03:46 +08:00
Alex Lam S.L
a841d45bc3 fix corner case in awaits (#5160)
fixes #5159
2021-10-31 23:46:55 +08:00
Alex Lam S.L
eb93d92357 fix corner case in awaits (#5158)
fixes #5157
2021-10-29 23:33:10 +08:00
Alex Lam S.L
a0250ec923 fix corner case in dead_code (#5154)
fixes #5153
2021-10-25 06:18:16 +08:00
Alex Lam S.L
25801627be parse let as symbol names correctly (#5151)
fixes #5149
2021-10-21 02:14:29 +08:00
Alex Lam S.L
32ae994f88 fix issues in tests flagged by LGTM (#5150) 2021-10-21 02:07:23 +08:00
Alex Lam S.L
03aec89f60 fix corner cases in strings & templates (#5147)
fixes #5145
2021-10-16 18:02:23 +08:00
Alex Lam S.L
faf0190546 document ECMAScript quirks (#5148)
- exclude Node.js v0.8 from CI as npm registry no longer works

closes #5146
2021-10-16 13:28:13 +08:00
Alex Lam S.L
c8b0f685ee fix corner case in merge_vars (#5143)
fixes #5142
2021-10-05 00:42:46 +08:00
Alex Lam S.L
87b99162fb fix corner case in inline (#5141)
fixes #5140
2021-10-02 06:54:42 +08:00
Alex Lam S.L
940887f20f fix corner case in evaluate (#5139)
fixes #5138
2021-10-01 02:52:21 +08:00
Alex Lam S.L
0b2573c3fa fix corner case in templates (#5137)
fixes #5136
2021-09-30 21:43:34 +08:00
Alex Lam S.L
157521066f avoid potential RegExp denial-of-service (#5135)
closes #5133
closes #5134
2021-09-30 01:49:46 +08:00
Alex Lam S.L
f766babf5e enhance templates (#5131)
closes #5125
2021-09-23 18:26:26 +08:00
Alex Lam S.L
436a29367c enhance dead_code (#5130) 2021-09-22 03:11:45 +08:00
Alex Lam S.L
55418fd460 fix corner case in rests (#5129)
fixes #5128
2021-09-20 05:02:35 +08:00
Alex Lam S.L
85786889bd v3.14.2 2021-09-07 21:52:59 +08:00
Alex Lam S.L
4b88dfb8d9 tweak test & warnings (#5123)
closes #5116
closes #5117
closes #5122
2021-09-07 01:33:23 +08:00
Alex Lam S.L
c3aef23614 fix corner case in reduce_vars (#5121)
fixes #5120
2021-08-25 10:39:35 +08:00
Alex Lam S.L
db94d21980 fix corner case in side_effects (#5118) 2021-08-23 08:51:59 +08:00
Alex Lam S.L
9634a9d1fd fix corner cases in optional_chains (#5110) 2021-08-20 10:10:10 +08:00
Alex Lam S.L
befb99bd71 fix corner case in inline (#5115)
fixes #5114
2021-08-18 15:57:08 +08:00
Alex Lam S.L
02eb8baa1c fix corner case in collapse_vars (#5113)
fixes #5112
2021-08-18 10:54:24 +08:00
Alex Lam S.L
c09f63aefb fix corner case in rests (#5109)
fixes #5108
2021-08-09 08:59:33 +08:00
Alex Lam S.L
fdcc6d3a9c fix corner case in dead_code (#5107)
fixes #5106
2021-08-06 08:35:11 +08:00
Alex Lam S.L
4fe2cac35e enhance inline (#5105) 2021-07-27 21:47:01 +08:00
Alex Lam S.L
e219a9a78a v3.14.1 2021-07-27 16:53:57 +08:00
Alex Lam S.L
c80eabd61e fix ie8 option alias (#5103)
fixes #5102
2021-07-26 16:45:43 +08:00
Alex Lam S.L
9b82f9be91 fix corner case in unused (#5101)
fixes #5100
2021-07-26 16:44:34 +08:00
Alex Lam S.L
657d525c80 fix corner case in reduce_vars (#5099)
fixes #5098
2021-07-24 07:10:14 +08:00
Alex Lam S.L
6a3fe9d1df fix corner cases in reduce_vars (#5097)
fixes #5096
2021-07-23 17:17:20 +08:00
62 changed files with 3726 additions and 857 deletions

View File

@@ -7,14 +7,9 @@ jobs:
test:
strategy:
matrix:
node: [ '0.8', '0.10', '0.12', '4', '6', '8', '10', '12', '14', latest ]
node: [ '0.10', '0.12', '4', '6', '8', '10', '12', '14', '16', latest ]
os: [ ubuntu-latest, windows-latest ]
script: [ compress, mocha, release/benchmark, release/jetstream ]
exclude:
- node: '0.8'
script: release/benchmark
- node: '0.8'
script: release/jetstream
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
runs-on: ${{ matrix.os }}
env:

View File

@@ -1199,6 +1199,17 @@ To allow for better optimizations, the compiler makes various assumptions:
- Object properties can be added, removed and modified (not prevented with
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
`Object.preventExtensions()` or `Object.seal()`).
- If array destructuring is present, index-like properties in `Array.prototype`
have not been overridden:
```javascript
Object.prototype[0] = 42;
var [ a ] = [];
var { 0: b } = {};
// 42 undefined
console.log([][0], a);
// 42 42
console.log({}[0], b);
```
- Earlier versions of JavaScript will throw `SyntaxError` with the following:
```javascript
({

View File

@@ -10,7 +10,9 @@ var info = require("../package.json");
var path = require("path");
var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "fixed", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
var skip_keys = [ "cname", "fixed", "in_arg", "inlined", "length_read", "parent_scope", "redef", "scope", "unused" ];
var truthy_keys = [ "optional", "pure", "terminal", "uses_arguments", "uses_eval", "uses_with" ];
var files = {};
var options = {};
var short_forms = {
@@ -430,7 +432,7 @@ function run() {
case "thedef":
return symdef(value);
}
if (skip_key(key)) return;
if (skip_property(key, value)) return;
if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return;
if (value instanceof UglifyJS.AST_Node) {
@@ -519,7 +521,7 @@ function read_file(path, default_value) {
}
function parse_js(value, options, flag) {
if (!options || typeof options != "object") options = {};
if (!options || typeof options != "object") options = Object.create(null);
if (typeof value == "string") try {
UglifyJS.parse(value, {
expression: true
@@ -559,8 +561,10 @@ function parse_js(value, options, flag) {
return options;
}
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
function skip_property(key, value) {
return skip_keys.indexOf(key) >= 0
// only skip truthy_keys if their value is falsy
|| truthy_keys.indexOf(key) >= 0 && !value;
}
function symdef(def) {

View File

@@ -50,6 +50,8 @@ function DEFNODE(type, props, methods, base) {
if (base && base.PROPS) props = props.concat(base.PROPS);
var code = [
"return function AST_", type, "(props){",
// not essential, but speeds up compress by a few percent
"this._bits=0;",
"if(props){",
];
props.forEach(function(prop) {
@@ -135,6 +137,52 @@ var AST_Node = DEFNODE("Node", "start end", {
},
}, null);
DEF_BITPROPS(AST_Node, [
"_optimized",
"_squeezed",
// AST_Call
"call_only",
"collapse_scanning",
// AST_SymbolRef
"defined",
"evaluating",
"falsy",
// AST_SymbolRef
"in_arg",
// AST_Return
"in_bool",
// AST_SymbolRef
"is_undefined",
// AST_LambdaExpression
// AST_LambdaDefinition
"inlined",
// AST_Lambda
"length_read",
// AST_Yield
"nested",
// AST_Lambda
"new",
// AST_Call
// AST_PropAccess
"optional",
// AST_ClassProperty
"private",
// AST_Call
"pure",
// AST_Assign
"redundant",
// AST_ClassProperty
"static",
// AST_Call
// AST_PropAccess
"terminal",
"truthy",
// AST_Scope
"uses_eval",
// AST_Scope
"uses_with",
]);
(AST_Node.log_function = function(fn, verbose) {
if (typeof fn != "function") {
AST_Node.info = AST_Node.warn = noop;
@@ -253,7 +301,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
},
}, AST_Statement);
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
@@ -484,7 +532,7 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
var AST_Scope = DEFNODE("Scope", "fn_defs may_call_this uses_eval uses_with", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
@@ -543,13 +591,13 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
}
}, AST_Scope);
var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", {
var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest safe_ids uses_arguments", {
$documentation: "Base class for functions",
$propdoc: {
argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
length_read: "[boolean/S] whether length property of this function is accessed",
rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent",
uses_arguments: "[boolean/S] whether this function accesses the arguments array",
uses_arguments: "[boolean|number/S] whether this function accesses the arguments array",
},
each_argname: function(visit) {
var tw = new TreeWalker(function(node) {
@@ -1289,13 +1337,14 @@ function must_be_expressions(node, prop, allow_spread, allow_hole) {
});
}
var AST_Call = DEFNODE("Call", "args expression optional pure", {
var AST_Call = DEFNODE("Call", "args expression optional pure terminal", {
$documentation: "A function call expression",
$propdoc: {
args: "[AST_Node*] array of arguments",
expression: "[AST_Node] expression to invoke as function",
optional: "[boolean] whether the expression is optional chaining",
pure: "[string/S] marker for side-effect-free call expression",
pure: "[boolean/S] marker for side-effect-free call expression",
terminal: "[boolean] whether the chain has ended",
},
walk: function(visitor) {
var node = this;
@@ -1316,6 +1365,7 @@ var AST_New = DEFNODE("New", null, {
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties",
_validate: function() {
if (this.optional) throw new Error("optional must be false");
if (this.terminal) throw new Error("terminal must be false");
},
}, AST_Call);
@@ -1338,12 +1388,18 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
},
});
var AST_PropAccess = DEFNODE("PropAccess", "expression optional property", {
function root_expr(prop) {
while (prop instanceof AST_PropAccess) prop = prop.expression;
return prop;
}
var AST_PropAccess = DEFNODE("PropAccess", "expression optional property terminal", {
$documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
$propdoc: {
expression: "[AST_Node] the “container” expression",
optional: "[boolean] whether the expression is optional chaining",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
terminal: "[boolean] whether the chain has ended",
},
get_property: function() {
var p = this.property;
@@ -1739,7 +1795,7 @@ var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable",
}, AST_SymbolDeclaration);
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", "unused", {
$documentation: "Symbol naming a function argument",
}, AST_SymbolVar);
@@ -1991,7 +2047,7 @@ TreeWalker.prototype = {
},
find_parent: function(type) {
var stack = this.stack;
for (var i = stack.length; --i >= 0;) {
for (var i = stack.length - 1; --i >= 0;) {
var x = stack[i];
if (x instanceof type) return x;
}

File diff suppressed because it is too large Load Diff

View File

@@ -97,7 +97,8 @@ function minify(files, options) {
var timings = options.timings && { start: Date.now() };
if (options.rename === undefined) options.rename = options.compress && options.mangle;
if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]);
if (options.ie || options.ie8) set_shorthand("ie", options, [ "compress", "mangle", "output" ]);
if (options.ie8) options.ie = options.ie || options.ie8;
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output" ]);
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]);

View File

@@ -556,7 +556,9 @@
return node;
},
ChainExpression: function(M) {
return from_moz(M.expression);
var node = from_moz(M.expression);
node.terminal = true;
return node;
},
};
@@ -868,7 +870,7 @@
def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
var computed = M instanceof AST_Sub;
return {
var expr = {
type: "MemberExpression",
object: to_moz(M.expression),
computed: computed,
@@ -878,6 +880,10 @@
name: M.property,
},
};
return M.terminal ? {
type: "ChainExpression",
expression: expr,
} : expr;
});
def_to_moz(AST_Unary, function To_Moz_Unary(M) {

View File

@@ -790,35 +790,26 @@ function OutputStream(options) {
if (p instanceof AST_Unary) return true;
});
function lhs_has_optional(node, output) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === node && is_lhs(p, output.parent(1))) {
// ++(foo?.bar).baz
// (foo?.()).bar = baz
do {
if (node.optional) return true;
node = node.expression;
} while (node.TYPE == "Call" || node instanceof AST_PropAccess);
}
function need_chain_parens(node, parent) {
if (!node.terminal) return false;
if (!(parent instanceof AST_Call || parent instanceof AST_PropAccess)) return false;
return parent.expression === node;
}
PARENS(AST_PropAccess, function(output) {
var node = this;
var p = output.parent();
if (p instanceof AST_New) {
if (p.expression !== node) return false;
// i.e. new (foo().bar)
//
// if there's one call into this subtree, then we need
// parens around it too, otherwise the call will be
// interpreted as passing the arguments to the upper New
// expression.
do {
node = node.expression;
} while (node instanceof AST_PropAccess);
return node.TYPE == "Call";
}
return lhs_has_optional(node, output);
// i.e. new (foo().bar)
//
// if there's one call into this subtree, then we need
// parens around it too, otherwise the call will be
// interpreted as passing the arguments to the upper New
// expression.
if (p instanceof AST_New && p.expression === node && root_expr(node).TYPE == "Call") return true;
// (foo?.bar)()
// (foo?.bar).baz
// new (foo?.bar)()
return need_chain_parens(node, p);
});
PARENS(AST_Call, function(output) {
@@ -833,7 +824,10 @@ function OutputStream(options) {
var g = output.parent(1);
if (g instanceof AST_Assign && g.left === p) return true;
}
return lhs_has_optional(node, output);
// (foo?.())()
// (foo?.()).bar
// new (foo?.())()
return need_chain_parens(node, p);
});
PARENS(AST_New, function(output) {
@@ -1158,8 +1152,9 @@ function OutputStream(options) {
});
}
function print_arrow(self, output) {
if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg && !self.rest) {
self.argnames[0].print(output);
var argname = self.argnames.length == 1 && !self.rest && self.argnames[0];
if (argname instanceof AST_SymbolFunarg && argname.name != "yield") {
argname.print(output);
} else {
print_funargs(self, output);
}
@@ -1470,7 +1465,7 @@ function OutputStream(options) {
parent = output.parent(level++);
if (parent instanceof AST_Call && parent.expression === node) return;
} while (parent instanceof AST_PropAccess && parent.expression === node);
output.print(typeof self.pure == "string" ? "/*" + self.pure + "*/" : "/*@__PURE__*/");
output.print("/*@__PURE__*/");
}
function print_call_args(self, output) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {

View File

@@ -44,10 +44,10 @@
"use strict";
var KEYWORDS = "break case catch class const continue debugger default delete do else extends finally for function if in instanceof let new return switch throw try typeof var void while with";
var KEYWORDS = "break case catch class const continue debugger default delete do else extends finally for function if in instanceof new return switch throw try typeof var void while with";
var KEYWORDS_ATOM = "false null true";
var RESERVED_WORDS = [
"abstract async await boolean byte char double enum export final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield",
"abstract async await boolean byte char double enum export final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield",
KEYWORDS_ATOM,
KEYWORDS,
].join(" ");
@@ -242,10 +242,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
read_template : with_eof_error("Unterminated template literal", function(strings) {
var s = "";
for (;;) {
var ch = next(true, true);
var ch = read();
switch (ch) {
case "\\":
ch += next(true, true);
ch += read();
break;
case "`":
strings.push(s);
@@ -260,6 +260,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
s += ch;
}
function read() {
var ch = next(true, true);
return ch == "\r" ? "\n" : ch;
}
}),
};
var prev_was_dot = false;
@@ -862,6 +867,15 @@ function parse($TEXT, options) {
next();
return import_();
}
break;
case "let":
if (is_vardefs()) {
next();
var node = let_();
semicolon();
return node;
}
break;
case "yield":
if (S.in_generator) return simple_statement();
break;
@@ -947,12 +961,6 @@ function parse($TEXT, options) {
next();
return if_();
case "let":
next();
var node = let_();
semicolon();
return node;
case "return":
if (S.in_function == 0 && !options.bare_returns)
croak("'return' outside of function");
@@ -1192,7 +1200,7 @@ function parse($TEXT, options) {
if (await || !is("punc", ";")) {
init = is("keyword", "const")
? (next(), const_(true))
: is("keyword", "let")
: is("name", "let") && is_vardefs()
? (next(), let_(true))
: is("keyword", "var")
? (next(), var_(true))
@@ -1308,6 +1316,11 @@ function parse($TEXT, options) {
}
if (node instanceof AST_SymbolFunarg) return node;
if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
if (node instanceof AST_Yield) return new AST_SymbolFunarg({
start: node.start,
name: "yield",
end: node.end,
});
token_error(node.start, "Invalid arrow parameter");
}
@@ -1535,12 +1548,18 @@ function parse($TEXT, options) {
}
var export_decl = embed_tokens(function() {
if (is("name", "async")) {
if (is("name")) switch (S.token.value) {
case "async":
next();
expect_token("keyword", "function");
if (!is("operator", "*")) return function_(AST_AsyncDefun);
next();
return function_(AST_AsyncGeneratorDefun);
case "let":
next();
var node = let_();
semicolon();
return node;
} else if (is("keyword")) switch (S.token.value) {
case "class":
next();
@@ -1555,11 +1574,6 @@ function parse($TEXT, options) {
if (!is("operator", "*")) return function_(AST_Defun);
next();
return function_(AST_GeneratorDefun);
case "let":
next();
var node = let_();
semicolon();
return node;
case "var":
next();
var node = var_();
@@ -1720,6 +1734,11 @@ function parse($TEXT, options) {
return a;
}
function is_vardefs() {
var token = peek();
return is_token(token, "name") || is_token(token, "punc", "[") || is_token(token, "punc", "{");
}
var const_ = function(no_in) {
return new AST_Const({
start : prev(),
@@ -1818,10 +1837,7 @@ function parse($TEXT, options) {
if (is("punc")) {
switch (start.value) {
case "`":
var tmpl = template(null);
tmpl.start = start;
tmpl.end = prev();
return subscripts(tmpl, allow_calls);
return subscripts(template(null), allow_calls);
case "(":
next();
if (is("punc", ")")) {
@@ -2133,7 +2149,7 @@ function parse($TEXT, options) {
}
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
if (sym.name == "arguments" || sym.name == "eval" || sym.name == "let")
token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
}
@@ -2230,6 +2246,7 @@ function parse($TEXT, options) {
}
function template(tag) {
var start = tag ? tag.start : S.token;
var read = S.input.context().read_template;
var strings = [];
var expressions = [];
@@ -2240,72 +2257,73 @@ function parse($TEXT, options) {
}
next();
return new AST_Template({
start: start,
expressions: expressions,
strings: strings,
tag: tag,
end: prev(),
});
}
var subscripts = function(expr, allow_calls, optional) {
function subscripts(expr, allow_calls) {
var start = expr.start;
if (is("punc", "[")) {
next();
var prop = expression();
expect("]");
return subscripts(new AST_Sub({
start: start,
optional: optional,
expression: expr,
property: prop,
end: prev(),
}), allow_calls);
}
if (allow_calls && is("punc", "(")) {
next();
var call = new AST_Call({
start: start,
optional: optional,
expression: expr,
args: expr_list(")", !options.strict),
end: prev(),
});
return subscripts(call, true);
}
if (optional || is("punc", ".")) {
if (!optional) next();
return subscripts(new AST_Dot({
start: start,
optional: optional,
expression: expr,
property: as_name(),
end: prev(),
}), allow_calls);
}
if (is("punc", "`")) {
var tmpl = template(expr);
tmpl.start = expr.start;
tmpl.end = prev();
return subscripts(tmpl, allow_calls);
}
if (is("operator", "?") && is_token(peek(), "punc", ".")) {
next();
next();
return subscripts(expr, allow_calls, true);
var optional = null;
while (true) {
if (is("operator", "?") && is_token(peek(), "punc", ".")) {
next();
next();
optional = expr;
}
if (is("punc", "[")) {
next();
var prop = expression();
expect("]");
expr = new AST_Sub({
start: start,
optional: optional === expr,
expression: expr,
property: prop,
end: prev(),
});
} else if (allow_calls && is("punc", "(")) {
next();
expr = new AST_Call({
start: start,
optional: optional === expr,
expression: expr,
args: expr_list(")", !options.strict),
end: prev(),
});
} else if (optional === expr || is("punc", ".")) {
if (optional !== expr) next();
expr = new AST_Dot({
start: start,
optional: optional === expr,
expression: expr,
property: as_name(),
end: prev(),
});
} else if (is("punc", "`")) {
if (optional) croak("Invalid template on optional chain");
expr = template(expr);
} else {
break;
}
}
if (optional) expr.terminal = true;
if (expr instanceof AST_Call && !expr.pure) {
var start = expr.start;
var comments = start.comments_before;
var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
while (--i >= 0) {
var match = /[@#]__PURE__/.exec(comments[i].value);
if (match) {
expr.pure = match[0];
if (/[@#]__PURE__/.test(comments[i].value)) {
expr.pure = true;
break;
}
}
}
return expr;
};
}
function maybe_unary(no_in) {
var start = S.token;

View File

@@ -44,7 +44,7 @@
"use strict";
var builtins = function() {
var names = [];
var names = new Dictionary();
// NaN will be included due to Number.NaN
[
"null",
@@ -72,10 +72,10 @@ var builtins = function() {
Object.getOwnPropertyNames(ctor.prototype).map(add);
}
});
return makePredicate(names);
return names;
function add(name) {
names.push(name);
names.set(name, true);
}
}();
@@ -116,9 +116,9 @@ function mangle_properties(ast, options) {
reserved: null,
}, true);
var reserved = Object.create(options.builtins ? null : builtins);
var reserved = options.builtins ? new Dictionary() : builtins.clone();
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
reserved[name] = true;
reserved.set(name, true);
});
var cname = -1;
@@ -126,7 +126,7 @@ function mangle_properties(ast, options) {
if (options.cache) {
cache = options.cache.props;
cache.each(function(name) {
reserved[name] = true;
reserved.set(name, true);
});
} else {
cache = new Dictionary();
@@ -141,8 +141,8 @@ function mangle_properties(ast, options) {
var debug_suffix;
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
var names_to_mangle = Object.create(null);
var unmangleable = Object.create(reserved);
var names_to_mangle = new Dictionary();
var unmangleable = reserved.clone();
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node) {
@@ -211,20 +211,20 @@ function mangle_properties(ast, options) {
// only function declarations after this line
function can_mangle(name) {
if (unmangleable[name]) return false;
if (unmangleable.has(name)) return false;
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true;
}
function should_mangle(name) {
if (reserved[name]) return false;
if (reserved.has(name)) return false;
if (regex && !regex.test(name)) return false;
return cache.has(name) || names_to_mangle[name];
return cache.has(name) || names_to_mangle.has(name);
}
function add(name) {
if (can_mangle(name)) names_to_mangle[name] = true;
if (!should_mangle(name)) unmangleable[name] = true;
if (can_mangle(name)) names_to_mangle.set(name, true);
if (!should_mangle(name)) unmangleable.set(name, true);
}
function mangle(name) {

View File

@@ -44,9 +44,9 @@
"use strict";
function SymbolDef(id, scope, orig, init) {
this._bits = 0;
this.defun = undefined;
this.eliminated = 0;
this.exported = false;
this.global = false;
this.id = id;
this.init = init;
this.mangled_name = null;
@@ -54,8 +54,8 @@ function SymbolDef(id, scope, orig, init) {
this.orig = [ orig ];
this.references = [];
this.replaced = 0;
this.safe_ids = undefined;
this.scope = scope;
this.undeclared = false;
}
SymbolDef.prototype = {
@@ -104,6 +104,15 @@ SymbolDef.prototype = {
},
};
DEF_BITPROPS(SymbolDef, [
"const_redefs",
"cross_loop",
"direct_access",
"exported",
"global",
"undeclared",
]);
var unary_side_effects = makePredicate("delete ++ --");
function is_lhs(node, parent) {
@@ -363,7 +372,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
if (node instanceof AST_SymbolLambda) {
var def = node.thedef;
if (!redefine(node, node.scope.parent_scope.resolve())) {
delete def.defun;
def.defun = undefined;
} else if (typeof node.thedef.init !== "undefined") {
node.thedef.init = false;
} else if (def.init) {
@@ -465,7 +474,7 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
for (var s = this.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (!options) {
delete s._var_names;
s._var_names = undefined;
} else if (options.keep_fnames) {
s.functions.each(function(d) {
push_uniq(def.scope.enclosed, d);
@@ -510,12 +519,12 @@ function names_in_use(scope, options) {
if (!names) {
scope.cname = -1;
scope.cname_holes = [];
scope.names_in_use = names = Object.create(null);
scope.names_in_use = names = new Dictionary();
var cache = options.cache && options.cache.props;
scope.enclosed.forEach(function(def) {
if (def.unmangleable(options)) names[def.name] = true;
if (def.unmangleable(options)) names.set(def.name, true);
if (def.global && cache && cache.has(def.name)) {
names[cache.get(def.name)] = true;
names.set(cache.get(def.name), true);
}
});
}
@@ -526,34 +535,33 @@ function next_mangled_name(def, options) {
var scope = def.scope;
var in_use = names_in_use(scope, options);
var holes = scope.cname_holes;
var names = Object.create(null);
var names = new Dictionary();
var scopes = [ scope ];
def.forEach(function(sym) {
var scope = sym.scope;
do {
if (scopes.indexOf(scope) < 0) {
for (var name in names_in_use(scope, options)) {
names[name] = true;
}
scopes.push(scope);
} else break;
if (member(scope, scopes)) break;
names_in_use(scope, options).each(function(marker, name) {
names.set(name, marker);
});
scopes.push(scope);
} while (scope = scope.parent_scope);
});
var name;
for (var i = 0; i < holes.length; i++) {
name = base54(holes[i]);
if (names[name]) continue;
if (names.has(name)) continue;
holes.splice(i, 1);
in_use[name] = true;
in_use.set(name, true);
return name;
}
while (true) {
name = base54(++scope.cname);
if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names[name]) break;
if (in_use.has(name) || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names.has(name)) break;
holes.push(scope.cname);
}
in_use[name] = true;
in_use.set(name, true);
return name;
}
@@ -598,7 +606,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
if (options.cache && options.cache.props) {
var mangled_names = names_in_use(this, options);
options.cache.props.each(function(mangled_name) {
mangled_names[mangled_name] = true;
mangled_names.set(mangled_name, true);
});
}

View File

@@ -77,21 +77,23 @@ function vlq_encode(num) {
}
function create_array_map() {
var map = Object.create(null);
var map = new Dictionary();
var array = [];
array.index = function(name) {
if (!HOP(map, name)) {
map[name] = array.length;
var index = map.get(name);
if (!(index >= 0)) {
index = array.length;
array.push(name);
map.set(name, index);
}
return map[name];
return index;
};
return array;
}
function SourceMap(options) {
var sources = create_array_map();
var sources_content = options.includeSources && Object.create(null);
var sources_content = options.includeSources && new Dictionary();
var names = create_array_map();
var mappings = "";
if (options.orig) Object.keys(options.orig).forEach(function(name) {
@@ -110,7 +112,7 @@ function SourceMap(options) {
if (!sources_content || !map.sourcesContent) return;
for (var i = 0; i < map.sources.length; i++) {
var content = map.sourcesContent[i];
if (content) sources_content[map.sources[i]] = content;
if (content) sources_content.set(map.sources[i], content);
}
});
var prev_source;
@@ -144,8 +146,8 @@ function SourceMap(options) {
add(source, gen_line, gen_col, orig_line, orig_col, name);
} : add,
setSourceContent: sources_content ? function(source, content) {
if (!(source in sources_content)) {
sources_content[source] = content;
if (!sources_content.has(source)) {
sources_content.set(source, content);
}
} : noop,
toString: function() {
@@ -155,7 +157,7 @@ function SourceMap(options) {
sourceRoot: options.root || undefined,
sources: sources,
sourcesContent: sources_content ? sources.map(function(source) {
return sources_content[source] || null;
return sources_content.get(source) || null;
}) : undefined,
names: names,
mappings: mappings,

View File

@@ -96,15 +96,6 @@ function defaults(args, defs, croak) {
return defs;
}
function merge(obj, ext) {
var count = 0;
for (var i in ext) if (HOP(ext, i)) {
obj[i] = ext[i];
count++;
}
return count;
}
function noop() {}
function return_false() { return false; }
function return_true() { return true; }
@@ -143,7 +134,7 @@ function push_uniq(array, el) {
}
function string_template(text, props) {
return text.replace(/\{([^}]+)\}/g, function(str, p) {
return text.replace(/\{([^{}]+)\}/g, function(str, p) {
var value = props[p];
return value instanceof AST_Node ? value.print_to_string() : value;
});
@@ -171,63 +162,80 @@ function all(array, predicate) {
}
function Dictionary() {
this._values = Object.create(null);
this._size = 0;
this.values = Object.create(null);
}
Dictionary.prototype = {
set: function(key, val) {
if (!this.has(key)) ++this._size;
this._values["$" + key] = val;
if (key == "__proto__") {
this.proto_value = val;
} else {
this.values[key] = val;
}
return this;
},
add: function(key, val) {
if (this.has(key)) {
this.get(key).push(val);
var list = this.get(key);
if (list) {
list.push(val);
} else {
this.set(key, [ val ]);
}
return this;
},
get: function(key) { return this._values["$" + key] },
get: function(key) {
return key == "__proto__" ? this.proto_value : this.values[key];
},
del: function(key) {
if (this.has(key)) {
--this._size;
delete this._values["$" + key];
if (key == "__proto__") {
delete this.proto_value;
} else {
delete this.values[key];
}
return this;
},
has: function(key) { return ("$" + key) in this._values },
has: function(key) {
return key == "__proto__" ? "proto_value" in this : key in this.values;
},
all: function(predicate) {
for (var i in this._values)
if (!predicate(this._values[i], i.substr(1)))
return false;
for (var i in this.values)
if (!predicate(this.values[i], i)) return false;
if ("proto_value" in this && !predicate(this.proto_value, "__proto__")) return false;
return true;
},
each: function(f) {
for (var i in this._values)
f(this._values[i], i.substr(1));
for (var i in this.values)
f(this.values[i], i);
if ("proto_value" in this) f(this.proto_value, "__proto__");
},
size: function() {
return this._size;
return Object.keys(this.values).length + ("proto_value" in this);
},
map: function(f) {
var ret = [];
for (var i in this._values)
ret.push(f(this._values[i], i.substr(1)));
for (var i in this.values)
ret.push(f(this.values[i], i));
if ("proto_value" in this) ret.push(f(this.proto_value, "__proto__"));
return ret;
},
clone: function() {
var ret = new Dictionary();
for (var i in this._values)
ret._values[i] = this._values[i];
ret._size = this._size;
this.each(function(value, i) {
ret.set(i, value);
});
return ret;
},
toObject: function() { return this._values }
toObject: function() {
var obj = {};
this.each(function(value, i) {
obj["$" + i] = value;
});
return obj;
},
};
Dictionary.fromObject = function(obj) {
var dict = new Dictionary();
dict._size = merge(dict._values, obj);
for (var i in obj)
if (HOP(obj, i)) dict.set(i.slice(1), obj[i]);
return dict;
};
@@ -265,3 +273,21 @@ function first_in_statement(stack, arrow, export_default) {
return false;
}
}
function DEF_BITPROPS(ctor, props) {
if (props.length > 31) throw new Error("Too many properties: " + props.length + "\n" + props.join(", "));
props.forEach(function(name, pos) {
var mask = 1 << pos;
Object.defineProperty(ctor.prototype, name, {
get: function() {
return !!(this._bits & mask);
},
set: function(val) {
if (val)
this._bits |= mask;
else
this._bits &= ~mask;
},
});
});
}

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.14.0",
"version": "3.14.5",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -442,9 +442,9 @@ compress_annotations_disabled_output_annotations_enabled: {
}
expect_exact: [
"/*@__PURE__*/a(3),",
"/*#__PURE__*/b(5),",
"/*@__PURE__*/b(5),",
"c(side_effect),",
"/*#__PURE__*/d(effect());",
"/*@__PURE__*/d(effect());",
]
}

View File

@@ -363,6 +363,28 @@ negate: {
}
inline_this: {
options = {
inline: true,
}
input: {
var p = "PASS";
console.log({
p: "FAIL",
q: (() => this.p)(),
}.q);
}
expect: {
var p = "PASS";
console.log({
p: "FAIL",
q: this.p,
}.q);
}
expect_stdout: "PASS"
node_version: ">=4"
}
dont_inline_this: {
options = {
inline: true,
}
@@ -556,7 +578,7 @@ reduce_iife_3: {
node_version: ">=4"
}
reduce_lambda: {
reduce_lambda_1: {
options = {
evaluate: true,
reduce_vars: true,
@@ -588,6 +610,43 @@ reduce_lambda: {
node_version: ">=4"
}
reduce_lambda_2: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function(f, a, b) {
f = () => {
console.log(a, b);
};
a = "foo", b = 42;
f();
b = "bar";
f();
})();
}
expect: {
(function(f, a, b) {
f = () => {
console.log("foo", b);
};
b = 42;
f();
b = "bar";
f();
})();
}
expect_stdout: [
"foo 42",
"foo bar",
]
node_version: ">=4"
}
single_use_recursive: {
options = {
reduce_vars: true,

View File

@@ -550,6 +550,24 @@ logical_side_effects: {
node_version: ">=15"
}
evaluate_lazy_assignment: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 42;
console.log(a &&= "PASS");
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4815_1: {
options = {
evaluate: true,

View File

@@ -227,7 +227,7 @@ inline_await_1_trim: {
console.log("PASS");
}
expect: {
void 0;
0;
console.log("PASS");
}
expect_stdout: "PASS"
@@ -340,6 +340,33 @@ inline_await_3_trim: {
node_version: ">=8"
}
inline_await_this: {
options = {
awaits: true,
inline: true,
}
input: {
var p = "FAIL";
({
p: "PASS",
async f() {
return await (async () => this.p)();
},
}).f().then(console.log);
}
expect: {
var p = "FAIL";
({
p: "PASS",
async f() {
return await this.p;
},
}).f().then(console.log);
}
expect_stdout: "PASS"
node_version: ">=8"
}
await_unary: {
options = {
awaits: true,
@@ -453,7 +480,7 @@ object_function: {
}).f();
}
expect: {
(async function() {
(async () => {
console.log("PASS");
})();
}
@@ -571,7 +598,7 @@ drop_async_1: {
}
expect: {
console.log(function(a) {
void (a *= 7);
a *= 7;
return a;
}(6));
}
@@ -1774,7 +1801,7 @@ issue_5001: {
}
expect: {
var a = 0;
void a++;
a++;
console.log(a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
@@ -2046,3 +2073,195 @@ issue_5070: {
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5157_async_function: {
options = {
awaits: true,
side_effects: true,
}
input: {
async function f() {
throw "FAIL";
}
(async function() {
try {
return await f();
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect: {
async function f() {
throw "FAIL";
}
(async function() {
try {
return await f();
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5157_async_iife: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function() {
try {
return await async function() {
throw "FAIL";
}();
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect: {
(async function() {
try {
return await async function() {
throw "FAIL";
}();
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5157_promise: {
options = {
awaits: true,
side_effects: true,
}
input: {
var p = new Promise(function(resolve, reject) {
reject("FAIL");
});
(async function() {
try {
return await p;
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect: {
var p = new Promise(function(resolve, reject) {
reject("FAIL");
});
(async function() {
try {
return await p;
} catch (e) {
return "PASS";
}
})().then(console.log);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5159_1: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function() {
try {
throw "foo";
} catch (e) {
return await "bar";
} finally {
console.log("baz");
}
})().catch(console.log).then(console.log);
console.log("moo");
}
expect: {
(async function() {
try {
throw "foo";
} catch (e) {
return await "bar";
} finally {
console.log("baz");
}
})().catch(console.log).then(console.log);
console.log("moo");
}
expect_stdout: [
"moo",
"baz",
"bar",
]
node_version: ">=8"
}
issue_5159_2: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function() {
try {
throw "foo";
} catch (e) {
return await "bar";
}
})().catch(console.log).then(console.log);
console.log("baz");
}
expect: {
(async function() {
try {
throw "foo";
} catch (e) {
return "bar";
}
})().catch(console.log).then(console.log);
console.log("baz");
}
expect_stdout: [
"baz",
"bar",
]
node_version: ">=8"
}
issue_5177: {
options = {
properties: true,
}
input: {
(async function() {
return {
p(await) {},
}.p;
})().then(function(a) {
console.log(typeof a);
});
}
expect: {
(async function() {
return {
p(await) {},
}.p;
})().then(function(a) {
console.log(typeof a);
});
}
expect_stdout: "function"
node_version: ">=8"
}

View File

@@ -4,7 +4,7 @@ arithmetic: {
}
expect_exact: "console.log((1n+0x2n)*(0o3n- -4n)>>5n-6n);"
expect_stdout: "42n"
node_version: ">=10"
node_version: ">=10.4.0"
}
minus_dot: {
@@ -13,7 +13,7 @@ minus_dot: {
}
expect_exact: "console.log(typeof-42n.toString(),typeof(-42n).toString());"
expect_stdout: "number string"
node_version: ">=10"
node_version: ">=10.4.0"
}
evaluate: {
@@ -28,7 +28,7 @@ evaluate: {
console.log(0xdeadbeefn.toString(16));
}
expect_stdout: "deadbeef"
node_version: ">=10"
node_version: ">=10.4.0"
}
Number: {
@@ -42,7 +42,7 @@ Number: {
console.log(+("" + -0xfeed_dead_beef_badn));
}
expect_stdout: "-1148098955808013200"
node_version: ">=10"
node_version: ">=10.4.0"
}
issue_4590: {
@@ -58,7 +58,7 @@ issue_4590: {
0n || console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=10"
node_version: ">=10.4.0"
}
issue_4801: {
@@ -88,5 +88,5 @@ issue_4801: {
}
}
expect_stdout: "PASS"
node_version: ">=10"
node_version: ">=10.4.0"
}

View File

@@ -2066,3 +2066,34 @@ issue_5082_2: {
expect_stdout: "PASS"
node_version: ">=12"
}
issue_5142: {
options = {
evaluate: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0, b;
if (++a)
new class {
p = b = null;
constructor(c) {
console.log(c ? "FAIL" : "PASS");
}
}(b, a);
}
expect: {
var a = 0, b;
if (++a)
new class {
p = b = null;
constructor(c) {
console.log(c ? "FAIL" : "PASS");
}
}(b, 1);
}
expect_stdout: "PASS"
node_version: ">=12"
}

View File

@@ -9253,13 +9253,13 @@ issue_4920_2: {
console.log(b);
}
expect: {
var o = {
var o;
var a = "PASS", b;
({
get PASS() {
a = "FAIL";
},
};
var a = "PASS", b;
o[b = a];
})[b = a];
console.log(b);
}
expect_stdout: "PASS"
@@ -9283,16 +9283,47 @@ issue_4920_3: {
}
expect: {
var log = console.log;
var o = {
var o;
var a = "PASS", b;
({
get PASS() {
a = "FAIL";
},
})[b = a];
log(b);
}
expect_stdout: "PASS"
}
issue_4920_4: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var o = {
get [(a = "FAIL 1", "PASS")]() {
a = "FAIL 2";
},
};
var a = "PASS", b;
o[b = a];
log(b);
}
expect: {
var log = console.log;
var o = {
get [(a = "FAIL 1", "PASS")]() {
a = "FAIL 2";
},
};
var a = "PASS", b;
o[b = a];
log(b);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4935: {
@@ -9412,3 +9443,126 @@ issue_4977_2: {
}
expect_stdout: "PASS PASS"
}
issue_5112_1: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
try {
try {
if (console + (a = "PASS", ""))
return "FAIL 1";
a.p;
} catch (e) {}
} finally {
return a;
}
}("FAIL 2"));
}
expect: {
console.log(function(a) {
try {
try {
if (console + (a = "PASS", ""))
return "FAIL 1";
a.p;
} catch (e) {}
} finally {
return a;
}
}("FAIL 2"));
}
expect_stdout: "PASS"
}
issue_5112_2: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
try {
return function() {
try {
if (console + (a = "PASS", ""))
return "FAIL 1";
a.p;
} catch (e) {}
}();
} finally {
return a;
}
}("FAIL 2"));
}
expect: {
console.log(function(a) {
try {
return function() {
try {
if (console + (a = "PASS", ""))
return "FAIL 1";
a.p;
} catch (e) {}
}();
} finally {
return a;
}
}("FAIL 2"));
}
expect_stdout: "PASS"
}
issue_5182: {
options = {
arrows: true,
collapse_vars: true,
evaluate: true,
hoist_props: true,
inline: true,
merge_vars: true,
passes: 4,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var con = console;
global.log = con.log;
var jump = function(x) {
console.log("JUMP:", x * 10);
return x + x;
};
var jump2 = jump;
var run = function(x) {
console.log("RUN:", x * -10);
return x * x;
};
var run2 = run;
var bar = (x, y) => {
console.log("BAR:", x + y);
return x - y;
};
var bar2 = bar;
var obj = {
foo: bar2,
go: run2,
not_used: jump2,
};
console.log(obj.foo(1, 2), global.log("PASS"));
}
expect: {
var con = console;
global.log = con.log,
console.log((console.log("BAR:", 3), -1), global.log("PASS"));
}
expect_stdout: [
"BAR: 3",
"PASS",
"-1 undefined",
]
node_version: ">=4"
}

View File

@@ -289,3 +289,18 @@ issue_3689: {
}
expect_stdout: "00"
}
issue_5145: {
options = {
strings: true,
}
input: {
var a = [];
console.log("" + a + ((a[0] = 4) + "2"));
}
expect: {
var a = [];
console.log("" + a + (a[0] = 4) + "2");
}
expect_stdout: "42"
}

View File

@@ -1633,3 +1633,39 @@ issue_5030: {
expect_stdout: "PASS"
node_version: ">=0.12"
}
issue_5106_1: {
options = {
dead_code: true,
}
input: {
console.log(typeof function(a) {
return a = arguments;
}("FAIL")[0]);
}
expect: {
console.log(typeof function(a) {
return a = arguments;
}("FAIL")[0]);
}
expect_stdout: "object"
}
issue_5106_2: {
options = {
dead_code: true,
}
input: {
"use strict";
console.log(function(a) {
return a = arguments;
}("PASS")[0]);
}
expect: {
"use strict";
console.log(function(a) {
return arguments;
}("PASS")[0]);
}
expect_stdout: "PASS"
}

View File

@@ -568,6 +568,20 @@ retain_empty_iife: {
node_version: ">=6"
}
drop_new_function: {
options = {
side_effects: true,
}
input: {
new function(a = console.log("PASS")) {}();
}
expect: {
void console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
retain_fargs: {
options = {
unused: true,
@@ -1023,7 +1037,7 @@ mangle_arrow_1: {
});
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.3"
}
mangle_arrow_1_toplevel: {
@@ -1059,7 +1073,7 @@ mangle_arrow_1_toplevel: {
});
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.3"
}
mangle_arrow_2: {
@@ -1095,7 +1109,7 @@ mangle_arrow_2: {
});
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.3"
}
mangle_arrow_2_toplevel: {
@@ -1131,7 +1145,7 @@ mangle_arrow_2_toplevel: {
});
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.3"
}
issue_4444: {
@@ -1573,7 +1587,7 @@ issue_4510_2: {
};
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4523: {
@@ -1890,3 +1904,56 @@ issue_5065: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5138_1: {
options = {
evaluate: true,
}
input: {
console.log(function(a, b = a = "FAIL") {
return a;
}() && "PASS");
}
expect: {
console.log(function(a, b = a = "FAIL") {
return a;
}() && "PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5138_2: {
options = {
evaluate: true,
}
input: {
console.log(function(a, b = a = "FAIL 1") {
return a;
}(null, "FAIL 2") || "PASS");
}
expect: {
console.log((null, "PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5192: {
options = {
dead_code: true,
ie: true,
}
input: {
(function a(a, [] = a = "PASS") {
console.log(a);
})("FAIL");
}
expect: {
(function a(a, [] = a = "PASS") {
console.log(a);
})("FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -220,7 +220,7 @@ funarg_side_effects_2: {
}
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.2"
}
funarg_side_effects_3: {
@@ -254,7 +254,7 @@ funarg_side_effects_3: {
}
}
expect_stdout: "PASS"
node_version: ">=6"
node_version: ">=6.9.2"
}
funarg_unused_1: {
@@ -1581,6 +1581,75 @@ hoist_vars: {
node_version: ">=6"
}
singleton_1: {
options = {
pure_getters: true,
side_effects: true,
unused: true,
}
input: {
var [ a ] = "P", b, o = {};
[ { 1: o.p } ] = [ "FAIL" ];
({ foo: [ o.q ] } = { foo: "S" });
[ b = "S" ] = [];
console.log(a + o.p + o.q + b);
}
expect: {
var b, a = "P"[0], o = {};
o.p = [ "FAIL"["1"] ][0];
o.q = { foo: "S"[0] }["foo"];
[ b = "S" ] = [];
console.log(a + o.p + o.q + b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
singleton_2: {
options = {
evaluate: true,
passes: 2,
pure_getters: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var [ a ] = "P", b, o = {};
[ { 1: o.p } ] = [ "FAIL" ];
({ foo: [ o.q ] } = { foo: "S" });
[ b = "S" ] = [];
console.log(a + o.p + o.q + b);
}
expect: {
var b, a = "P", o = {};
o.p = "A";
o.q = "S";
[ b = "S" ] = [];
console.log(a + o.p + o.q + b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
singleton_side_effects: {
options = {
side_effects: true,
unused: true,
}
input: {
[ 42[console.log("foo")] ] = [ console.log("bar") ];
}
expect: {
[ 42[console.log("foo")] ] = [ console.log("bar") ];
}
expect_stdout: [
"bar",
"foo",
]
node_version: ">=6"
}
issue_4280: {
options = {
evaluate: true,
@@ -2127,7 +2196,7 @@ issue_4372_2: {
}
expect: {
var a;
[ a ] = [ "PASS", "FAIL" ];
[ a ] = a = [ "PASS", "FAIL" ];
console.log(a);
}
expect_stdout: "PASS"
@@ -3057,3 +3126,243 @@ issue_5087_2: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5114_1: {
options = {
inline: true,
unused: true,
}
input: {
var a = "PASS";
(function({}, a) {})(42);
console.log(a);
}
expect: {
var a = "PASS";
[ {} ] = [ 42 ],
void 0;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5114_2: {
options = {
inline: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = "PASS";
(function f([], a) {
f.length;
})([]);
console.log(a);
}
expect: {
var a = "PASS";
0;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5114_3: {
options = {
inline: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = "PASS";
(function f(a, {}) {
f.length;
})(null, 42);
console.log(a);
}
expect: {
var a = "PASS";
0;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5153_array_assign: {
options = {
dead_code: true,
}
input: {
var a = function*() {
yield b;
}(), b;
[ b ] = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect: {
var a = function*() {
yield b;
}(), b;
[ b ] = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5153_array_var: {
options = {
dead_code: true,
}
input: {
var a = function*() {
yield b;
}(), [ b ] = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect: {
var a = function*() {
yield b;
}(), [ b ] = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5153_object_assign: {
options = {
dead_code: true,
}
input: {
var a = {
get p() {
return b;
},
}, b;
({
p: b
} = b = a);
console.log(a === b ? "PASS" : "FAIL");
}
expect: {
var a = {
get p() {
return b;
},
}, b;
({
p: b
} = b = a);
console.log(a === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5153_object_var: {
options = {
dead_code: true,
}
input: {
var a = {
get p() {
return b;
},
}, {
p: b
} = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect: {
var a = {
get p() {
return b;
},
}, {
p: b
} = b = a;
console.log(a === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5168: {
options = {
collapse_vars: true,
}
input: {
(function a({
[console.log(typeof function() {
++a;
return a;
}())]: b,
}) {
var a;
})({});
}
expect: {
(function a({
[console.log(typeof function() {
++a;
return a;
}())]: b,
}) {
var a;
})({});
}
expect_stdout: "function"
node_version: ">=6"
}
issue_5189_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 42;
[ a.p ] = a = "PASS";
console.log(a);
}
expect: {
var a;
[ a.p ] = a = "PASS";
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5189_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 42;
({ p: a.q } = a = "PASS");
console.log(a);
}
expect: {
var a;
({ p: a.q } = a = "PASS");
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -1557,9 +1557,9 @@ issue_2665: {
}
expect: {
var a = 1;
!function g() {
(function g() {
a-- && g();
}();
})();
console.log(a);
}
expect_stdout: "-1"
@@ -2916,7 +2916,7 @@ issue_4133: {
console.log(a);
}
expect: {
var b = 1;
var a = 1;
console.log(0);
}
expect_stdout: "0"
@@ -3062,7 +3062,7 @@ issue_4184: {
expect_stdout: "42"
}
issue_4235: {
issue_4235_1: {
options = {
inline: true,
reduce_vars: true,
@@ -3081,13 +3081,37 @@ issue_4235: {
}
expect: {
void function() {
var f;
console.log(f);
var f = console.log(f);
}();
}
expect_stdout: "undefined"
}
issue_4235_2: {
options = {
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unused: true,
varify: true,
}
input: {
(function() {
{
const f = 0;
}
(function f() {
var f = console.log(f);
})();
})();
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
}
issue_4404: {
options = {
pure_getters: "strict",
@@ -3379,7 +3403,7 @@ issue_4834: {
}
expect: {
try {
void b.p;
b.p;
} catch (e) {
console.log("PASS");
}

View File

@@ -3203,7 +3203,7 @@ issue_4552: {
expect_stdout: "NaN"
}
issue_4886: {
issue_4886_1: {
options = {
evaluate: true,
unsafe: true,
@@ -3222,3 +3222,23 @@ issue_4886: {
}
expect_stdout: "true"
}
issue_4886_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log("foo" in {
"foo": null,
__proto__: 42,
});
}
expect: {
console.log("foo" in {
"foo": null,
__proto__: 42,
});
}
expect_stdout: "true"
}

View File

@@ -62,7 +62,7 @@ assignment_2: {
}
expect_exact: "var a=8n;a**=a;console.log(a);"
expect_stdout: "16777216n"
node_version: ">=10"
node_version: ">=10.4.0"
}
evaluate: {
@@ -99,8 +99,8 @@ issue_4664: {
expect: {
(function f() {
new function(a) {
console.log(typeof f, 1073741824, typeof this);
}(A = 0);
console.log(typeof f, a, typeof this);
}((A = 0, 2 ** 30));
})();
}
expect_stdout: "function 1073741824 object"

View File

@@ -1171,11 +1171,11 @@ issue_2620_4: {
}
expect: {
var c = "FAIL";
!function() {
(function() {
switch (NaN) {
case void (c = "PASS"):
}
}();
})();
console.log(c);
}
expect_stdout: "PASS"
@@ -4857,8 +4857,9 @@ issue_4155: {
}
expect: {
(function() {
void console.log(b);
var b = function() {};
var a;
void console.log(a);
function b() {}
b && console.log(typeof b);
})();
}
@@ -6413,3 +6414,291 @@ issue_5067: {
}
expect: {}
}
issue_5096_1: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a, b = "FAIL", c = 1;
do {
a && a();
a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect: {
var a, b = "FAIL", c = 1;
do {
a && a();
a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect_stdout: "PASS"
}
issue_5096_2: {
options = {
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a, b = "FAIL", c = 1;
do {
a && a();
a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect: {
var a, b = "FAIL", c = 1;
do {
a && a();
a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect_stdout: "PASS"
}
issue_5096_3: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var b = "FAIL", c = 1;
do {
a && a();
var a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect: {
var b = "FAIL", c = 1;
do {
a && a();
var a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect_stdout: "PASS"
}
issue_5096_4: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var b = "FAIL", c = 1;
do {
a && a();
var a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect: {
var b = "FAIL", c = 1;
do {
a && a();
var a = function() {
b = "PASS";
};
} while (c--);
console.log(b);
}
expect_stdout: "PASS"
}
issue_5098: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(o) {
function f() {
f = console.log;
if (o.p++)
throw "FAIL";
f("PASS");
}
return f;
})({ p: 0 })();
}
expect: {
(function(o) {
function f() {
f = console.log;
if (o.p++)
throw "FAIL";
f("PASS");
}
return f;
})({ p: 0 })();
}
expect_stdout: "PASS"
}
shorter_without_void: {
options = {
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a;
function f(b) {
a = b;
}
f("foo");
console.log(a) || f("bar");
console.log(a, f("baz"));
console.log(a);
}
expect: {
var a;
function f(b) {
a = b;
}
a = "foo";
console.log(a) || (a = "bar");
console.log(a, f("baz"));
console.log(a);
}
expect_stdout: [
"foo",
"bar undefined",
"baz",
]
}
issue_5120: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function f() {
function g() {
f || g();
}
g();
return f.valueOf();
};
console.log(a() === a ? "PASS" : "FAIL");
}
expect: {
function a() {
(function g() {
a || g();
})();
return a.valueOf();
}
console.log(a() === a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_5140: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
A = 42;
function f(b) {
return b >> 0;
}
var a = f(42 in []);
console.log(f(A));
}
expect: {
function f(b) {
return b >> 0;
}
A = 42;
console.log(A >> 0);
}
expect_stdout: "42"
}
issue_5173_1: {
options = {
conditionals: true,
inline: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
function f(a, b) {
console.log(b);
}
f([ A = 42, [] + "" || (A = f) ]);
}
expect: {
function f(a, b) {
console.log(b);
}
f([ A = 42, [] + "" || (A = f) ]);
}
expect_stdout: "undefined"
}
issue_5173_2: {
options = {
conditionals: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a, b) {
console.log(b);
}
f([ A = 42, [] + "" || (A = f) ]);
}
expect: {
function f(a, b) {
console.log(b);
}
f(A = [] + "" ? 42 : f);
}
expect_stdout: "undefined"
}

View File

@@ -217,7 +217,8 @@ name_collision_1: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj_foo$0 = 3,
var obj,
obj_foo$0 = 3,
obj_bar = 4,
obj_b_r = 5,
obj_b_r$0 = 6,
@@ -249,7 +250,8 @@ name_collision_2: {
console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
var o,
o_p = 1,
o__ = function(x) {
return x;
},
@@ -283,7 +285,8 @@ name_collision_3: {
console.log(o.p === o.p, o["+"](4), o["-"](5));
}
expect: {
var o_p = 1,
var o,
o_p = 1,
o__ = function(x) {
return x;
},
@@ -315,7 +318,7 @@ name_collision_4: {
}
expect: {
console.log(function() {
var o_p$0 = 0, o_q = "PASS";
var o, o_p$0 = 0, o_q = "PASS";
return function(o_p) {
if (!o_p$0) return o_p;
}(o_q);
@@ -768,7 +771,7 @@ issue_3046: {
expect: {
console.log(function(a) {
do {
var b_c = a++;
var b, b_c = a++;
} while (b_c && a);
return a;
}(0));
@@ -931,7 +934,7 @@ issue_3411: {
expect: {
var c = 1;
!function f() {
var o_p = --c && f();
var o, o_p = --c && f();
+{} || console.log("PASS");
}();
}
@@ -1042,9 +1045,7 @@ issue_3945_1: {
expect: {
function f() {
o.p;
var o = {
q: 0,
};
var o, o_q = 0;
}
}
}
@@ -1063,9 +1064,7 @@ issue_3945_2: {
}
expect: {
console.log(typeof o);
var o = {
p: 0,
};
var o, o_p = 0;
}
expect_stdout: "undefined"
}
@@ -1134,10 +1133,46 @@ issue_4985: {
}());
}
expect: {
var a_p = 42;
var a, a_p = 42;
console.log(function() {
({});
}());
}
expect_stdout: "undefined"
}
issue_5182: {
options = {
hoist_props: true,
merge_vars: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var o = console;
log = o.log;
o = {
p: function(a) {
console.log(a ? "PASS" : "FAIL");
return a;
},
};
log(o.p(42));
}
expect: {
var o_p = console;
log = o_p.log;
o_p = function(a) {
console.log(a ? "PASS" : "FAIL");
return a;
};
log(o_p(42));
}
expect_stdout: [
"PASS",
"42",
]
}

View File

@@ -135,7 +135,7 @@ issue_2295: {
}
}
issue_4487: {
issue_4487_1: {
options = {
functions: true,
hoist_vars: true,
@@ -150,16 +150,64 @@ issue_4487: {
};
var b = a();
}
expect: {
var a = function f() {
var f = console.log(typeof f);
};
a();
}
expect_stdout: "undefined"
}
issue_4487_2: {
options = {
functions: true,
hoist_vars: true,
keep_fnames: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function f() {
var f = console.log(typeof f);
};
var b = a();
}
expect: {
function a() {
var f;
console.log(typeof f);
var f = console.log(typeof f);
}
a();
}
expect_stdout: "undefined"
}
issue_4487_3: {
options = {
functions: true,
hoist_vars: true,
keep_fnames: true,
passes: 3,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function f() {
var f = console.log(typeof f);
};
var b = a();
}
expect: {
(function a() {
console.log(typeof void 0);
})();
}
expect_stdout: "undefined"
}
issue_4489: {
options = {
collapse_vars: true,
@@ -251,18 +299,18 @@ issue_4839: {
unused: true,
}
input: {
var o = function(a, b) {
var log = console.log, o = function(a, b) {
return b && b;
}("foo");
for (var k in o)
throw "FAIL";
console.log("PASS");
log("PASS");
}
expect: {
var k, o = void 0;
for (k in o)
var k, log = console.log;
for (k in void 0)
throw "FAIL";
console.log("PASS");
log("PASS");
}
expect_stdout: "PASS"
}
@@ -288,8 +336,7 @@ issue_4859: {
}
expect: {
(function f(a) {
var d = 1 / 0, d = Infinity;
console.log(d);
console.log(Infinity);
return f;
})();
}
@@ -395,3 +442,61 @@ issue_4898: {
}
expect_stdout: "PASS"
}
issue_5187: {
options = {
hoist_props: true,
hoist_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {
var a = 42;
do {
var b = { 0: a++ };
} while (console.log(b[b ^= 0]));
}
f();
}
expect: {
(function() {
var b, a = 42;
do {
b = { 0: a++ };
} while (console.log(b[b ^= 0]));
})();
}
expect_stdout: "42"
}
issue_5195: {
options = {
hoist_props: true,
hoist_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {
var a;
do {
var b = { p: a };
} while (console.log(b += ""));
}
f();
}
expect: {
(function() {
var a, b;
do {
b = { p: a };
} while (console.log(b += ""));
})();
}
expect_stdout: "[object Object]"
}

View File

@@ -489,6 +489,116 @@ join_object_assignments_regex: {
expect_stdout: "1"
}
chained_assignments: {
options = {
join_vars: true,
}
input: {
var a, b = a = {};
b.p = "PASS";
console.log(a.p);
}
expect: {
var a, b = a = {
p: "PASS",
};
console.log(a.p);
}
expect_stdout: "PASS"
}
folded_assignments_1: {
options = {
evaluate: true,
join_vars: true,
}
input: {
var a = {};
a[a.PASS = 42] = "PASS";
console.log(a[42], a.PASS);
}
expect: {
var a = {
PASS: 42,
42: "PASS",
};
console.log(a[42], a.PASS);
}
expect_stdout: "PASS 42"
}
folded_assignments_2: {
options = {
evaluate: true,
join_vars: true,
}
input: {
"use strict";
var a = {};
a[42] = "FAIL";
a[a.PASS = 42] = "PASS";
console.log(a[42], a.PASS);
}
expect: {
"use strict";
var a = {
42: "FAIL",
PASS: 42,
};
a[42] = "PASS";
console.log(a[42], a.PASS);
}
expect_stdout: "PASS 42"
}
inlined_assignments: {
options = {
join_vars: true,
unused: true,
}
input: {
var a;
(a = {}).p = "PASS";
console.log(a.p);
}
expect: {
var a = {
p: "PASS",
};
console.log(a.p);
}
expect_stdout: "PASS"
}
typescript_enum: {
rename = true
options = {
assignments: true,
collapse_vars: true,
evaluate: true,
hoist_props: true,
inline: true,
join_vars: true,
passes: 4,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var Enum;
(function (Enum) {
Enum[Enum.PASS = 42] = "PASS";
})(Enum || (Enum = {}));
console.log(Enum[42], Enum.PASS);
}
expect: {
console.log("PASS", 42);
}
expect_stdout: "PASS 42"
}
issue_2816: {
options = {
join_vars: true,
@@ -1183,3 +1293,26 @@ assign_sequence_var: {
"1 2 3",
]
}
issue_5175: {
options = {
join_vars: true,
}
input: {
function log(f) {
console.log(f(), A.p);
}
log(function() {
return (A = {}).p = "PASS";
});
}
expect: {
function log(f) {
console.log(f(), A.p);
}
log(function() {
return (A = {}).p = "PASS";
});
}
expect_stdout: "PASS PASS"
}

View File

@@ -83,8 +83,9 @@ labels_5: {
conditionals: true,
dead_code: true,
if_return: true,
unused: true,
}
// should keep the break-s in the following
// should keep `break`s below
input: {
while (foo) {
if (bar) break;
@@ -100,8 +101,8 @@ labels_5: {
if (bar) break;
console.log("foo");
}
out: while (foo) {
if (bar) break out;
while (foo) {
if (bar) break;
console.log("foo");
}
}
@@ -189,23 +190,22 @@ labels_10: {
conditionals: true,
dead_code: true,
if_return: true,
unused: true,
}
input: {
out: while (foo) {
x();
y();
out: while (42) {
console.log("PASS");
break out;
z();
k();
console.log("FAIL");
}
};
expect: {
out: while (foo) {
x();
y();
break out;
while (42) {
console.log("PASS");
break;
}
}
expect_stdout: "PASS"
}
issue_4466_1: {

View File

@@ -476,9 +476,9 @@ issue_4112: {
try {
throw 42;
} catch (e) {
var a = e;
for (e in a);
a = function() {};
var o = e;
for (e in o);
function a() {}
console.log(typeof a);
return a;
}
@@ -3377,3 +3377,60 @@ issue_4956_2: {
}
expect_stdout: "42"
}
issue_5182: {
options = {
arrows: true,
collapse_vars: true,
evaluate: true,
hoist_props: true,
inline: true,
merge_vars: true,
passes: 4,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
try {
var con = console;
} catch (x) {}
global.log = con.log;
var jump = function(x) {
console.log("JUMP:", x * 10);
return x + x;
};
var jump2 = jump;
var run = function(x) {
console.log("RUN:", x * -10);
return x * x;
};
var run2 = run;
var bar = (x, y) => {
console.log("BAR:", x + y);
return x - y;
};
var bar2 = bar;
var obj = {
foo: bar2,
go: run2,
not_used: jump2,
};
console.log(obj.foo(1, 2), global.log("PASS"));
}
expect: {
try {
var con = console;
} catch (x) {}
global.log = con.log,
console.log((console.log("BAR:", 3), -1), global.log("PASS"));
}
expect_stdout: [
"BAR: 3",
"PASS",
"-1 undefined",
]
node_version: ">=4"
}

View File

@@ -521,3 +521,25 @@ issue_4415: {
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5213: {
options = {
objects: true,
}
input: {
var a = "FAIL";
console.log({
p: a = "PASS",
0: a,
p: null,
}[0]);
}
expect: {
var a = "FAIL";
console.log({
p: (a = "PASS", null),
0: a,
}[0]);
}
expect_stdout: "PASS"
}

View File

@@ -58,7 +58,7 @@ assign_parentheses_dot: {
input: {
(console?.log).name.p = console.log("PASS");
}
expect_exact: '(console?.log.name).p=console.log("PASS");'
expect_exact: '(console?.log).name.p=console.log("PASS");'
expect_stdout: "PASS"
node_version: ">=14"
}
@@ -72,6 +72,26 @@ assign_no_parentheses: {
node_version: ">=14"
}
call_parentheses: {
input: {
(function(o) {
console.log(o.f("FAIL"), (o.f)("FAIL"), (0, o.f)(42));
console.log(o?.f("FAIL"), (o?.f)("FAIL"), (0, o?.f)(42));
})({
a: "PASS",
f(b) {
return this.a || b;
},
});
}
expect_exact: '(function(o){console.log(o.f("FAIL"),o.f("FAIL"),(0,o.f)(42));console.log(o?.f("FAIL"),(o?.f)("FAIL"),(0,o?.f)(42))})({a:"PASS",f(b){return this.a||b}});'
expect_stdout: [
"PASS PASS 42",
"PASS PASS 42",
]
node_version: ">=14"
}
unary_parentheses: {
input: {
var o = { p: 41 };
@@ -237,6 +257,99 @@ trim_2: {
node_version: ">=14"
}
trim_dot_call_1: {
options = {
evaluate: true,
optional_chains: true,
}
input: {
console.log(null?.f());
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
node_version: ">=14"
}
trim_dot_call_2: {
options = {
evaluate: true,
optional_chains: true,
unsafe: true,
}
input: {
try {
(null?.p)();
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
(void 0)();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=14"
}
trim_dot_call_3: {
options = {
evaluate: true,
optional_chains: true,
unsafe: true,
}
input: {
try {
({ p: null })?.p();
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
null();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=14"
}
trim_dot_sub: {
options = {
evaluate: true,
optional_chains: true,
}
input: {
console.log(null?.p[42]);
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
node_version: ">=14"
}
trim_sub_call_call: {
options = {
evaluate: true,
optional_chains: true,
}
input: {
console.log(null?.[42]()());
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
node_version: ">=14"
}
issue_4906: {
options = {
toplevel: true,

View File

@@ -1510,3 +1510,71 @@ issue_5093_quote_style: {
expect_exact: 'console.log({a:true,\'42\':"PASS","null":[]}[6*7]);'
expect_stdout: "PASS"
}
object_methods: {
options = {
properties: true,
}
input: {
({
p() {
console.log("FAIL 1");
},
*q() {
console.log("FAIL 2");
},
async r() {
console.log("FAIL 3");
},
async *s() {
console.log("PASS");
},
}).s().next();
}
expect: {
[
() => {
console.log("FAIL 1");
},
function*() {
console.log("FAIL 2");
},
async () => {
console.log("FAIL 3");
},
async function*() {
console.log("PASS");
},
][3]().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5177: {
options = {
properties: true,
}
input: {
var a = "FAIL";
var o = { a: "PASS" };
o.p = {
q() {
return this.a;
},
}.q;
console.log(o.p());
}
expect: {
var a = "FAIL";
var o = { a: "PASS" };
o.p = {
q() {
return this.a;
},
}.q;
console.log(o.p());
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -1640,6 +1640,26 @@ nested_property_assignments_3: {
expect_stdout: "PASS"
}
nested_property_assignments_4: {
options = {
pure_getters: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var n, o = { p: { q: { r: "PASS" } } };
(n = o.p).r = n.q.r;
console.log(o.p.r);
}
expect: {
var n, o = { p: { q: { r: "PASS" } } };
(n = o.p).r = n.q.r;
console.log(o.p.r);
}
expect_stdout: "PASS"
}
issue_4939: {
options = {
pure_getters: "strict",

View File

@@ -7320,6 +7320,64 @@ local_assignment_loop: {
expect_stdout: "PASS"
}
local_assignment_modified: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a;
(a = a || {}).p = 42;
console.log(a.p);
}
expect: {
var a;
(a = {}).p = 42;
console.log(a.p);
}
expect_stdout: "42"
}
local_declaration: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a;
a || console.log(a = "PASS");
}
expect: {
var a;
console.log("PASS");
}
expect_stdout: "PASS"
}
local_definition_modified: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = a || {};
a.p = 42;
console.log(a.p);
}
expect: {
var a = {};
a.p = 42;
console.log(a.p);
}
expect_stdout: "42"
}
issue_3957_1: {
options = {
evaluate: true,
@@ -7435,6 +7493,7 @@ issue_4030: {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}

View File

@@ -51,7 +51,7 @@ arrow_destructured_object_1: {
}
expect_exact: "var f=({...a})=>a,o=f({PASS:42});for(var k in o)console.log(k,o[k]);"
expect_stdout: "PASS 42"
node_version: ">=8"
node_version: ">=8.3.0"
}
arrow_destructured_object_2: {
@@ -62,7 +62,7 @@ arrow_destructured_object_2: {
}
expect_exact: "var f=({FAIL:a,...b})=>b,o=f({PASS:42,FAIL:null});for(var k in o)console.log(k,o[k]);"
expect_stdout: "PASS 42"
node_version: ">=8"
node_version: ">=8.3.0"
}
arrow_destructured_object_3: {
@@ -79,7 +79,7 @@ arrow_destructured_object_3: {
"2 S",
"3 S",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
funarg_1: {
@@ -131,7 +131,7 @@ destructured_object_1: {
}
expect_exact: 'var{...a}=["FAIL","PASS",42];console.log(a[1],a[2]);'
expect_stdout: "PASS 42"
node_version: ">=8"
node_version: ">=8.3.0"
}
destructured_object_2: {
@@ -141,7 +141,7 @@ destructured_object_2: {
}
expect_exact: 'var{0:a,...b}=["FAIL","PASS",42];console.log(b[1],b[2]);'
expect_stdout: "PASS 42"
node_version: ">=8"
node_version: ">=8.3.0"
}
drop_fargs: {
@@ -231,7 +231,7 @@ reduce_destructured_object: {
console.log(a[0]);
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
retain_destructured_array: {
@@ -270,7 +270,7 @@ retain_destructured_object_1: {
"1 PASS",
"2 42",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
retain_destructured_object_2: {
@@ -292,7 +292,7 @@ retain_destructured_object_2: {
"bar PASS",
"baz 42",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
retain_funarg_destructured_array_1: {
@@ -344,7 +344,7 @@ retain_funarg_destructured_object_1: {
console.log((({ ...a }) => a)([ "PASS" ])[0]);
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
retain_funarg_destructured_object_2: {
@@ -362,7 +362,7 @@ retain_funarg_destructured_object_2: {
}({ p: "FAIL" }).p || "PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
drop_unused_call_args_1: {
@@ -482,7 +482,7 @@ merge_funarg_destructured_object: {
})([ "PASS" ]);
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_arguments: {
@@ -636,6 +636,24 @@ keep_rest_lambda_2: {
node_version: ">=6"
}
drop_new_function: {
options = {
side_effects: true,
}
input: {
new function(...{
[console.log("PASS")]: a,
}) {}();
}
expect: {
void ([ ... {
[console.log("PASS")]: [].e,
}] = []);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4525_1: {
options = {
arguments: true,
@@ -974,7 +992,7 @@ issue_5089_1: {
console.log(o.p);
}
expect_stdout: "undefined"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_5089_2: {
@@ -1001,5 +1019,189 @@ issue_5089_2: {
console.log(o.p);
}
expect_stdout: "undefined"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_5100_1: {
options = {
passes: 2,
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a;
[ {
p: {},
...a
} ] = [ {
p: {
q: a,
} = 42,
r: "PASS",
} ];
console.log(a.r);
}
expect: {
var a;
({
p: {},
...a
} = [ {
p: [ a = 42["q"] ],
r: "PASS",
} ][0]);
console.log(a.r);
}
expect_stdout: "PASS"
node_version: ">=8.3.0"
}
issue_5100_2: {
options = {
passes: 2,
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a;
[ {
p: {},
...a
} ] = [ {
p: (console.log("PASS"), {
q: a,
} = 42),
} ];
}
expect: {
var a;
({
p: {},
...a
} = [ {
p: [ console.log("PASS"), a = 42["q"] ],
} ][0]);
}
expect_stdout: "PASS"
node_version: ">=10.22.0"
}
issue_5108: {
options = {
evaluate: true,
reduce_vars: true,
rests: true,
unsafe: true,
unused: true,
}
input: {
console.log(function([ ...[ a ] ]) {
return a;
}([ "PASS", "FAIL" ]));
}
expect: {
console.log(function([]) {
return "PASS";
}([ "PASS", "FAIL" ]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5128_1: {
options = {
inline: true,
}
input: {
console.log(function() {
return function f(...[ a ]) {
return a;
}("PASS");
}());
}
expect: {
console.log(function f(...[ a ]) {
return a;
}("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5128_2: {
options = {
inline: true,
keep_fnames: true,
unused: true,
}
input: {
console.log(function() {
return function f(...[ a ]) {
return a;
}("PASS");
}());
}
expect: {
console.log(function f(...[ a ]) {
return a;
}("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5165_1: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
reduce_vars: true,
rests: true,
side_effects: true,
switches: true,
unsafe: true,
}
input: {
console.log(function([ ...a ]) {
switch (a) {
case a:
return "PASS";
}
}([]));
}
expect: {
console.log(function([ ...a ]) {
return "PASS";
}([]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5165_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
reduce_vars: true,
rests: true,
side_effects: true,
switches: true,
unsafe: true,
}
input: {
console.log(function(...a) {
switch (a) {
case a:
return "PASS";
}
}());
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -201,3 +201,20 @@ issue_4811_2: {
expect_stdout: "PASS [object global] true"
node_version: ">=8"
}
issue_5197: {
rename = true
input: {
function f(async) {
async(")=>{}");
}
console.log("" + this.__proto__);
}
expect: {
function f(a) {
a(")=>{}");
}
console.log("" + this.__proto__);
}
expect_stdout: "[object global]"
}

View File

@@ -341,7 +341,7 @@ convert_setter: {
console.log(k, o[k]);
}
expect_stdout: "PASS undefined"
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_getter_1: {
@@ -370,7 +370,7 @@ keep_getter_1: {
});
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_getter_2: {
@@ -399,7 +399,7 @@ keep_getter_2: {
"foo",
"bar",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_getter_3: {
@@ -429,7 +429,7 @@ keep_getter_3: {
});
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_getter_4: {
@@ -460,7 +460,7 @@ keep_getter_4: {
});
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
keep_accessor: {
@@ -508,7 +508,7 @@ keep_accessor: {
"q undefined",
"r null",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
object_key_order_1: {
@@ -538,7 +538,7 @@ object_key_order_1: {
"a 3",
"b 2",
]
node_version: ">=8 <=10"
node_version: ">=8.3.0 <=10"
}
object_key_order_2: {
@@ -568,7 +568,7 @@ object_key_order_2: {
"a 3",
"b 2",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
object_key_order_3: {
@@ -598,7 +598,7 @@ object_key_order_3: {
"a 3",
"b 2",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
object_key_order_4: {
@@ -628,7 +628,7 @@ object_key_order_4: {
"a 3",
"b 2",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
object_spread_array: {
@@ -654,7 +654,7 @@ object_spread_array: {
"0 foo",
"1 bar",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
object_spread_string: {
@@ -681,7 +681,7 @@ object_spread_string: {
"1 o",
"2 o",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
unused_var_side_effects: {
@@ -711,7 +711,7 @@ unused_var_side_effects: {
});
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
unsafe_join_1: {
@@ -793,7 +793,7 @@ issue_4329: {
}[0]);
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4331: {
@@ -871,7 +871,7 @@ issue_4345: {
}[42]);
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4361: {
@@ -901,7 +901,7 @@ issue_4361: {
"foo",
"undefined",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4363: {
@@ -922,7 +922,7 @@ issue_4363: {
});
}
expect_stdout: "PASS"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4556: {
@@ -994,7 +994,7 @@ issue_4849: {
}()));
}
expect_stdout: "object"
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4882_1: {
@@ -1026,7 +1026,7 @@ issue_4882_1: {
"PASS",
"undefined",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4882_2: {
@@ -1052,7 +1052,7 @@ issue_4882_2: {
"42",
"PASS",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_4882_3: {
@@ -1082,7 +1082,7 @@ issue_4882_3: {
"PASS",
"42",
]
node_version: ">=8"
node_version: ">=8.3.0"
}
issue_5006: {

View File

@@ -131,6 +131,105 @@ malformed_escape: {
node_version: ">=4"
}
booleans: {
options = {
booleans: true,
evaluate: true,
templates: true,
}
input: {
var a;
console.log(`$${a}${a}` ? "PASS" : "FAIL");
}
expect: {
var a;
console.log("$" + a + a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}
escape_placeholder_1: {
options = {
templates: true,
}
input: {
console.log(`\${\n`);
}
expect: {
console.log(`\${
`);
}
expect_stdout: [
"${",
"",
]
node_version: ">=4"
}
escape_placeholder_2: {
options = {
evaluate: true,
templates: true,
}
input: {
console.log(`\n${"${"}\n`);
}
expect: {
console.log(`
\${
`);
}
expect_stdout: [
"",
"${",
"",
]
node_version: ">=4"
}
escape_placeholder_3: {
options = {
evaluate: true,
templates: true,
}
input: {
console.log(`\n$${"{"}\n`);
}
expect: {
console.log(`
\${
`);
}
expect_stdout: [
"",
"${",
"",
]
node_version: ">=4"
}
escape_placeholder_4: {
options = {
evaluate: true,
templates: true,
}
input: {
console.log(`\n${"$"}${"{"}\n`);
}
expect: {
console.log(`
\${
`);
}
expect_stdout: [
"",
"${",
"",
]
node_version: ">=4"
}
evaluate: {
options = {
evaluate: true,
@@ -174,7 +273,7 @@ partial_evaluate: {
console.log(`${6 * 7} foo ${console ? `PA` + "SS" : `FA` + `IL`}`);
}
expect: {
console.log(`42 foo ${console ? "PASS" : "FAIL"}`);
console.log("42 foo " + (console ? "PASS" : "FAIL"));
}
expect_stdout: "42 foo PASS"
node_version: ">=4"
@@ -204,7 +303,7 @@ malformed_evaluate_2: {
console.log(`\u0${0}b${5}`);
}
expect: {
console.log(`\u0${0}b5`);
console.log(`\u00b` + 5);
}
expect_stdout: true
node_version: ">=4"
@@ -238,7 +337,7 @@ malformed_evaluate_4: {
console.log("\\u00b5");
}
expect_stdout: "\\u00b5"
node_version: ">=8"
node_version: ">=8.10.0"
}
unsafe_evaluate: {
@@ -254,7 +353,7 @@ unsafe_evaluate: {
console.log("\\uFo");
}
expect_stdout: "\\uFo"
node_version: ">=8"
node_version: ">=8.10.0"
}
side_effects_1: {
@@ -357,13 +456,14 @@ issue_4604: {
issue_4606: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`${typeof A} ${"\r"} ${"\\"} ${"`"}`);
}
expect: {
console.log(`${typeof A} \r \\ \``);
console.log(typeof A + " \r \\ `");
}
expect_stdout: "undefined \r \\ `"
node_version: ">=4"
@@ -434,3 +534,238 @@ issue_4931: {
]
node_version: ">=4"
}
issue_5125_1: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`PASS ${typeof A}`);
}
expect: {
console.log("PASS " + typeof A);
}
expect_stdout: "PASS undefined"
node_version: ">=4"
}
issue_5125_2: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`PASS
${typeof A}`);
}
expect: {
console.log(`PASS
` + typeof A);
}
expect_stdout: [
"PASS",
"undefined",
]
node_version: ">=4"
}
issue_5125_3: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`PASS\n${typeof A}`);
}
expect: {
console.log(`PASS
` + typeof A);
}
expect_stdout: [
"PASS",
"undefined",
]
node_version: ">=4"
}
issue_5125_4: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`PASS
${typeof A}`);
}
expect: {
console.log(`PASS
` + typeof A);
}
expect_stdout: [
"PASS",
"",
"undefined",
]
node_version: ">=4"
}
issue_5125_5: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`PASS\n\n${typeof A}`);
}
expect: {
console.log(`PASS
` + typeof A);
}
expect_stdout: [
"PASS",
"",
"undefined",
]
node_version: ">=4"
}
issue_5125_6: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`${typeof A} ${typeof B} PASS`);
}
expect: {
console.log(typeof A + ` ${typeof B} PASS`);
}
expect_stdout: "undefined undefined PASS"
node_version: ">=4"
}
issue_5125_7: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`${typeof A} ${typeof B} ${typeof C} PASS`);
}
expect: {
console.log(typeof A + ` ${typeof B} ${typeof C} PASS`);
}
expect_stdout: "undefined undefined undefined PASS"
node_version: ">=4"
}
issue_5125_8: {
options = {
evaluate: true,
strings: true,
templates: true,
}
input: {
console.log(`${typeof A}${typeof B}${typeof C} PASS`);
}
expect: {
console.log(typeof A + typeof B + typeof C + " PASS");
}
expect_stdout: "undefinedundefinedundefined PASS"
node_version: ">=4"
}
issue_5136: {
options = {
templates: true,
}
input: {
console.log(`${A = []}${A[0] = 42}`);
}
expect: {
console.log(`` + (A = []) + (A[0] = 42));
}
expect_stdout: "42"
node_version: ">=4"
}
issue_5145_1: {
options = {
strings: true,
templates: true,
}
input: {
var a = [];
console.log(`${a}${a[0] = 42}
`);
}
expect: {
var a = [];
console.log(`${a}${a[0] = 42}
`);
}
expect_stdout: [
"42",
"",
]
node_version: ">=4"
}
issue_5145_2: {
options = {
strings: true,
templates: true,
}
input: {
var a = [];
console.log(`${a}${a}${a[0] = 42}
`);
}
expect: {
var a = [];
console.log("" + a + a + (a[0] = 42) + `
`);
}
expect_stdout: [
"42",
"",
]
node_version: ">=4"
}
issue_5199: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function() {
console.log(typeof b);
}``;
{
const b = a;
}
}
expect: {
var a = function() {
console.log(typeof b);
}``;
{
const b = a;
}
}
expect_stdout: "undefined"
node_version: ">=4"
}

View File

@@ -67,7 +67,8 @@ unicode_escaped_identifier_2: {
}
expect_exact: 'var a="foo";var \u{10000}="bar";console.log(a,\u{10000});'
expect_stdout: "foo bar"
node_version: ">=4"
// non-BMP support is platform-dependent on Node.js v4
node_version: ">=6"
}
unicode_identifier_ascii_only: {
@@ -200,7 +201,8 @@ surrogate_pair: {
}
expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);'
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
node_version: ">=4"
// non-BMP support is platform-dependent on Node.js v4
node_version: ">=6"
}
surrogate_pair_ascii: {
@@ -216,5 +218,6 @@ surrogate_pair_ascii: {
}
expect_exact: 'var \\u{2f800}={"\\ud87e\\udc01":"\\udbc0\\udc00"};\\u{2f800}.\\u{2f802}="\\udbc0\\udc01";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\ud87e\\udc02"]);'
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
node_version: ">=4"
// non-BMP support is platform-dependent on Node.js v4
node_version: ">=6"
}

View File

@@ -111,7 +111,7 @@ hoist_props_const: {
}
}
expect: {
var o_p = "PASS";
var o = 0, o_p = "PASS";
console.log(o_p);
}
expect_stdout: "PASS"
@@ -136,7 +136,7 @@ hoist_props_let: {
}
expect: {
"use strict";
var o_p = "PASS";
var o, o_p = "PASS";
console.log(o_p);
}
expect_stdout: "PASS"

View File

@@ -96,7 +96,7 @@ pause_resume: {
node_version: ">=4"
}
arrow_yield: {
arrow_yield_1: {
input: {
yield = "PASS";
console.log(function*() {
@@ -108,6 +108,18 @@ arrow_yield: {
node_version: ">=4"
}
arrow_yield_2: {
input: {
console.log(typeof function *() {
// Syntax error on Node.js v6+
return (yield) => {};
}().next().value);
}
expect_exact: "console.log(typeof function*(){return(yield)=>{}}().next().value);"
expect_stdout: "function"
node_version: "4"
}
for_of: {
input: {
function* f() {
@@ -958,7 +970,7 @@ issue_4639_1: {
}().next().value());
}
expect_stdout: "PASS"
node_version: ">=4"
node_version: ">=4 <7 || >=8.7.0"
}
issue_4639_2: {
@@ -1275,3 +1287,25 @@ issue_5076: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5177: {
options = {
properties: true,
}
input: {
console.log(typeof function*() {
return {
p(yield) {},
}.p;
}().next().value);
}
expect: {
console.log(typeof function*() {
return {
p(yield) {},
}.p;
}().next().value);
}
expect_stdout: "function"
node_version: ">=4"
}

View File

@@ -0,0 +1 @@
console?.log``;

View File

@@ -1,7 +1,5 @@
// (beautified)
console.log(function() {
return 1 + .1 + .1;
}());
console.log(1 + .1 + .1);
// output: 1.2000000000000002
//
// minify: 1.2

View File

@@ -68,6 +68,8 @@ if (typeof phantom == "undefined") {
(function install() {
npm([
"install",
"graceful-fs@4.2.6",
"is-my-json-valid@2.20.5",
"phantomjs-prebuilt@2.1.14",
"--no-audit",
"--no-optional",

View File

@@ -721,6 +721,20 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should throw syntax error (console?.log``)", function(done) {
var command = uglifyjscmd + " test/input/invalid/optional-template.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/optional-template.js:1,12",
"console?.log``;",
" ^",
"ERROR: Invalid template on optional chain",
].join("\n"));
done();
});
});
it("Should handle literal string as source map input", function(done) {
var command = [
uglifyjscmd,

View File

@@ -191,7 +191,7 @@ describe("comments", function() {
});
it("Should correctly preserve new lines around comments", function() {
var tests = [
[
[
"// foo",
"// bar",

View File

@@ -1,7 +1,6 @@
var assert = require("assert");
var exec = require("child_process").exec;
var path = require("path");
var readFileSync = require("fs").readFileSync;
describe("bin/uglifyjs with input file globs", function() {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var UglifyJS = require("../..");
var UglifyJS = require("../node");
describe("let", function() {
this.timeout(30000);
@@ -54,4 +54,43 @@ describe("let", function() {
assert.notStrictEqual(result.indexOf('v["' + name + '"]'), -1);
});
});
it("Should parse `let` as name correctly", function() {
[
"for(var let;let;let)let;",
"function let(let){let}",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
assert.strictEqual(ast.print_to_string(), code);
assert.throws(function() {
UglifyJS.parse('"use strict";' + code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error && e.message == "Unexpected let in strict mode";
}, code);
});
});
it("Should throw on ambiguous use of `let`", function() {
[
"export let",
[
"let",
"console.log(42)",
].join("\n"),
[
"let",
"[ console.log(42) ]",
].join("\n"),
[
"let",
"{",
" console.log(42)",
"}",
].join("\n"),
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
});

View File

@@ -25,7 +25,7 @@ describe("minify", function() {
if (result.error) throw result.error;
assert.strictEqual(result.code, "print(42);");
assert.strictEqual(JSON.stringify(options), value);
})
});
it("Should skip inherited keys from `files`", function() {
var files = Object.create({ skip: this });
files[0] = "alert(1 + 1)";

View File

@@ -1,5 +1,4 @@
var assert = require("assert");
var exec = require("child_process").exec;
var fs = require("fs");
var reduce_test = require("../reduce");
var semver = require("semver");
@@ -282,35 +281,40 @@ describe("test/reduce.js", function() {
});
if (result.error) throw result.error;
assert.deepEqual(result.warnings, []);
assert.strictEqual(result.code.replace(/function \(/g, "function("), (semver.satisfies(process.version, "<=0.10") ? [
"// Can't reproduce test failure",
"// minify options: {",
'// "compress": false,',
'// "mangle": false,',
'// "output": {',
'// "beautify": true',
"// }",
"// }",
] : [
[
"try{",
"null[function(){}]",
"}catch(e){",
"console.log(e)",
"}",
].join(""),
"// output: TypeError: Cannot read property 'function(){}' of null",
"// ",
"// minify: TypeError: Cannot read property 'function() {}' of null",
"// ",
"// options: {",
'// "compress": false,',
'// "mangle": false,',
'// "output": {',
'// "beautify": true',
"// }",
"// }",
]).join("\n"));
if (semver.satisfies(process.version, "<=0.10")) {
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "compress": false,',
'// "mangle": false,',
'// "output": {',
'// "beautify": true',
"// }",
"// }",
].join("\n"));
} else {
var message = result.code.split(/\n/, 3)[1].slice("// output: ".length);
assert.strictEqual(result.code, [
[
"try{",
"null[function(){}]",
"}catch(e){",
"console.log(e)",
"}",
].join(""),
"// output: " + message,
"// ",
"// minify: " + message.replace("(){}", "() {}"),
"// ",
"// options: {",
'// "compress": false,',
'// "mangle": false,',
'// "output": {',
'// "beautify": true',
"// }",
"// }",
].join("\n"));
}
});
it("Should maintain block-scope for const/let", function() {
if (semver.satisfies(process.version, "<4")) return;

View File

@@ -362,7 +362,7 @@ describe("sourcemaps", function() {
it("Should not modify input source map", function() {
var orig = get_map();
var original = JSON.stringify(orig);
var map = prepare_map(orig);
prepare_map(orig);
assert.strictEqual(JSON.stringify(orig), original);
});
it("Should copy over original sourcesContent", function() {

View File

@@ -4,34 +4,27 @@ var UglifyJS = require("../..");
describe("spidermonkey export/import sanity test", function() {
it("Should produce a functional build when using --self with spidermonkey", function(done) {
this.timeout(60000);
this.timeout(120000);
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
uglifyjs + " -p spidermonkey -cm";
exec(command, {
maxBuffer: 1048576
}, function(err, stdout) {
var command = [
uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey",
uglifyjs + " -p spidermonkey -cm",
].join(" | ");
exec(command, { maxBuffer: 1048576 }, function(err, stdout) {
if (err) throw err;
eval(stdout);
assert.strictEqual(typeof SpiderUglify, "object");
var result = SpiderUglify.minify("foo([true,,2+3]);");
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, "foo([!0,,5]);");
done();
});
});
it("Should not add unnecessary escape slashes to regexps", function() {
it("Should not add unnecessary escape slashes to RegExp", function() {
var input = "/[\\\\/]/;";
var ast = UglifyJS.parse(input).to_mozilla_ast();
assert.equal(
UglifyJS.AST_Node.from_mozilla_ast(ast).print_to_string(),
input
);
assert.strictEqual(UglifyJS.AST_Node.from_mozilla_ast(ast).print_to_string(), input);
});
it("Should judge between directives and strings correctly on import", function() {

View File

@@ -12,7 +12,7 @@ describe("String literals", function() {
'"\u2029"',
].forEach(function(input) {
assert.throws(function() {
var ast = UglifyJS.parse(input);
UglifyJS.parse(input);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unterminated string constant";
@@ -44,7 +44,7 @@ describe("String literals", function() {
'"use strict";\n"\\011"',
].forEach(function(input) {
assert.throws(function() {
var output = UglifyJS.parse(input);
UglifyJS.parse(input);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";

View File

@@ -34,20 +34,20 @@ describe("Template literals", function() {
[
// native line breaks
[ "`foo\nbar`", "`foo\nbar`" ],
[ "`foo\rbar`", "`foo\rbar`" ],
[ "`foo\rbar`", "`foo\nbar`" ],
[ "`foo\r\nbar`", "`foo\nbar`" ],
[ "`foo\r\n\rbar`", "`foo\n\rbar`" ],
[ "`foo\r\n\rbar`", "`foo\n\nbar`" ],
// escaped line breaks
[ "`foo\\nbar`", "`foo\\nbar`" ],
[ "`foo\\rbar`", "`foo\\rbar`" ],
[ "`foo\r\\nbar`", "`foo\r\\nbar`" ],
[ "`foo\r\\nbar`", "`foo\n\\nbar`" ],
[ "`foo\\r\nbar`", "`foo\\r\nbar`" ],
[ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ],
// continuation
[ "`foo\\\nbar`", "`foo\\\nbar`" ],
[ "`foo\\\rbar`", "`foo\\\rbar`" ],
[ "`foo\\\rbar`", "`foo\\\nbar`" ],
[ "`foo\\\r\nbar`", "`foo\\\nbar`" ],
[ "`foo\\\r\n\rbar`", "`foo\\\n\rbar`" ],
[ "`foo\\\r\n\rbar`", "`foo\\\n\nbar`" ],
[ "`foo\\\\nbar`", "`foo\\\\nbar`" ],
[ "`foo\\\\rbar`", "`foo\\\\rbar`" ],
[ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ],

View File

@@ -215,9 +215,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
// hoist and return expressions from the IIFE function expression
var seq = [];
node.expression.body.forEach(function(node) {
var expr = expr 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)) {
// collect expressions from each statements' body
// collect expressions from each statement's body
seq.push(expr);
}
});
@@ -395,7 +395,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
var expr = [
node.expression, // switch expression
node.body[0] && node.body[0].expression, // first case expression or undefined
node.body[0] && node.body[0], // first case body or undefined
node.body[0], // first case body or undefined
][ (node.start._permute * steps | 0) % 4 ];
node.start._permute += step;
if (expr && (!(expr instanceof U.AST_Statement) || !has_loopcontrol(expr, node, parent))) {

View File

@@ -28,7 +28,7 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
if ([
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
/\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/,
/\basync([ \t]+|[ \t]*#|[ \t]*\*[ \t]*)[^\s()[\]{},.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
/\basync([ \t]+|[ \t]*#|[ \t]*\*[ \t]*)[^\s()[\]{}#:;,.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
].some(function(pattern) {
return pattern.test(code);
})) {
@@ -51,13 +51,13 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
};
exports.patch_module_statements = function(code) {
var count = 0, imports = [];
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(/\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 (!header) return "";
if (header.length == 1) return "0, " + header;
return header.slice(0, -1) + " _" + ++count + header.slice(-1);
}).replace(/\bimport\.meta\b/g, function() {
return '({ url: "https://example.com/path/index.html" })';
}).replace(/\bimport\b(?:\s*([^('"]+)\bfrom\b)?\s*(['"]).*?\2(?:$|\n|;)/g, function(match, symbols) {
}).replace(/\bimport\b(?:\s*([^\s('"][^('"]*)\bfrom\b)?\s*(['"]).*?\2(?:$|\n|;)/g, function(match, symbols) {
if (symbols) {
if (!/^[{*]/.test(symbols)) symbols = "default:" + symbols;
symbols = symbols.replace(/[{}]/g, "").trim().replace(/\s*,\s*/g, ",");
@@ -202,13 +202,11 @@ function setup(global, builtins, setup_log, setup_tty) {
});
Object.defineProperties(global, props);
// for Node.js v8+
if (global.toString !== Object.prototype.toString) {
global.__proto__ = Object.defineProperty(Object.create(global.__proto__), "toString", {
value: function() {
return "[object global]";
},
});
}
global.__proto__ = Object.defineProperty(Object.create(global.__proto__), "toString", {
value: function() {
return "[object global]";
},
});
function self() {
return this;
@@ -254,8 +252,11 @@ function run_code_vm(code, toplevel, timeout) {
var ctx = vm.createContext({ console: console });
// for Node.js v6
vm.runInContext(setup_code, ctx);
vm.runInContext(toplevel ? "(function(){" + code + "})();" : code, ctx, { timeout: timeout });
return strip_color_codes(stdout);
vm.runInContext(toplevel ? "(function(){\n" + code + "\n})();" : code, ctx, { timeout: timeout });
// for Node.js v4
return strip_color_codes(stdout.replace(/\b(Array \[|Object {)/g, function(match) {
return match.slice(-1);
}));
} catch (ex) {
return ex;
} finally {
@@ -265,7 +266,7 @@ function run_code_vm(code, toplevel, timeout) {
function run_code_exec(code, toplevel, timeout) {
if (toplevel) {
code = setup_code + "(function(){" + code + "})();";
code = setup_code + "(function(){\n" + code + "\n})();";
} else {
code = code.replace(/^((["'])[^"']*\2(;|$))?/, function(directive) {
return directive + setup_code;
@@ -278,11 +279,11 @@ function run_code_exec(code, toplevel, timeout) {
timeout: timeout || 5000,
});
if (result.status === 0) return result.stdout;
var msg = ("" + result.stderr).replace(/\r\n/g, "\n");
if (result.error && result.error.code == "ETIMEDOUT" || /FATAL ERROR:/.test(msg)) {
return new Error("Script execution timed out.");
}
if (result.error) return result.error;
var msg = result.stderr.replace(/\r\n/g, "\n");
var end = msg.indexOf("\n\n-----===== UNCAUGHT EXCEPTION =====-----\n\n");
var details;
if (end >= 0) {
@@ -294,7 +295,7 @@ function run_code_exec(code, toplevel, timeout) {
} catch (e) {}
}
var match = /\n([^:\s]*Error)(?:: ([\s\S]+?))?\n( at [\s\S]+)\n$/.exec(msg);
if (!match) return details;
if (!match) return details || new Error("Script execution aborted.");
var ex = new global[match[1]](match[2]);
ex.stack = ex.stack.slice(0, ex.stack.indexOf(" at ")) + match[3];
if (typeof details == "object") {

View File

@@ -334,6 +334,7 @@ var VAR_NAMES = [
"arguments",
"async",
"await",
"let",
"yield",
];
var INITIAL_NAMES_LEN = VAR_NAMES.length;
@@ -352,7 +353,7 @@ var TYPEOF_OUTCOMES = [
];
var avoid_vars = [];
var block_vars = [];
var block_vars = [ "let" ];
var lambda_vars = [];
var unique_vars = [];
var classes = [];
@@ -399,7 +400,7 @@ function mayDefer(code) {
function createTopLevelCode() {
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
block_vars.length = 0;
block_vars.length = 1;
lambda_vars.length = 0;
unique_vars.length = 0;
classes.length = 0;
@@ -2027,6 +2028,7 @@ function removeAvoidVar(name) {
function isBannedKeyword(name) {
switch (name) {
case "arguments":
case "let":
return in_class;
case "await":
return async !== false;
@@ -2078,8 +2080,8 @@ if (require.main !== module) {
return;
}
function run_code(code, toplevel) {
return sandbox.run_code(sandbox.patch_module_statements(code), toplevel);
function run_code(code, toplevel, timeout) {
return sandbox.run_code(sandbox.patch_module_statements(code), toplevel, timeout);
}
function writeln(stream, msg) {
@@ -2350,7 +2352,7 @@ function patch_try_catch(orig, toplevel) {
tries: [],
} ];
var tail_throw = '\nif (typeof UFUZZ_ERROR == "object") throw UFUZZ_ERROR;\n';
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)[{]+)\)|}\s*finally)\s*(?={)/g;
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^()[{]+)\)|}\s*finally)\s*(?={)/g;
while (stack.length) {
var code = stack[0].code;
var offset = stack[0].offset;
@@ -2467,8 +2469,10 @@ for (var round = 1; round <= num_iterations; round++) {
println("original result:");
println(result);
println();
// ignore v8 parser bug
return bug_async_arrow_rest(result);
// ignore v8 parser bug
return bug_async_arrow_rest(result)
// ignore runtime platform bugs
|| result.message == "Script execution aborted.";
})) continue;
minify_options.forEach(function(options) {
var o = JSON.parse(options);
@@ -2483,6 +2487,8 @@ for (var round = 1; round <= num_iterations; round++) {
ok = sandbox.same_stdout(original_result, uglify_result);
// ignore v8 parser bug
if (!ok && bug_async_arrow_rest(uglify_result)) ok = true;
// ignore runtime platform bugs
if (!ok && uglify_result.message == "Script execution aborted.") ok = true;
// handle difference caused by time-outs
if (!ok && errored && is_error_timeout(original_result)) {
if (is_error_timeout(uglify_result)) {