Compare commits

..

63 Commits

Author SHA1 Message Date
Alex Lam S.L
fb1bff2c0a v3.17.4 2022-10-24 01:46:19 +08:00
Alex Lam S.L
19c471c16a fix corner cases in reduce_vars (#5717)
fixes #5716
2022-10-19 23:22:19 +08:00
Alex Lam S.L
8319badea8 fix corner case in merge_vars (#5715)
fixes #5714
2022-10-17 11:19:43 +08:00
Alex Lam S.L
5a5200d657 fix corner case in conditionals (#5713)
fixes #5712
2022-10-14 23:55:08 +08:00
Alex Lam S.L
5411360829 fix corner case in if_return (#5711)
fixes #5710
2022-10-13 22:34:55 +01:00
Alex Lam S.L
7edd10e5e5 fix corner case in unused (#5708)
fixes #5707
2022-10-10 21:45:57 +08:00
Alex Lam S.L
bccb1c3bd9 fix corner case in unused (#5706)
fixes #5705
2022-10-10 08:02:23 +08:00
Alex Lam S.L
ed7051b9bb enhance side_effects & strings (#5704) 2022-10-10 08:01:40 +08:00
Alex Lam S.L
a391897388 enhance conditionals (#5703) 2022-10-08 09:59:33 +08:00
Alex Lam S.L
4a1da492dd v3.17.3 2022-10-06 02:14:42 +08:00
Alex Lam S.L
94a954c3d1 minor clean-ups (#5701) 2022-10-06 02:06:21 +08:00
Alex Lam S.L
be8ccc3ab5 fix corner case in varify (#5698)
fixes #5697
2022-10-04 16:03:24 +08:00
Alex Lam S.L
58d997a3d6 fix corner case in booleans & conditionals (#5696) 2022-10-04 12:58:55 +08:00
Alex Lam S.L
dabcc39b51 fix corner cases in booleans & conditionals (#5695)
fixes #5694
2022-10-03 22:47:15 +08:00
Alex Lam S.L
140e4e0da8 fix corner case in inline (#5693)
fixes #5692
2022-10-03 08:01:56 +08:00
Alex Lam S.L
80fc862547 enhance assignments, booleans & conditionals (#5691) 2022-10-03 08:01:23 +08:00
Alex Lam S.L
6cdc035b2f fix corner case in if_return (#5689)
fixes #5688
2022-09-30 06:49:51 +08:00
Alex Lam S.L
e1e3516397 fix corner case in reduce_vars (#5687) 2022-09-30 02:00:37 +08:00
Alex Lam S.L
bd5fc4cb1b implement mangle.properties.domprops (#5686)
- support destructuring syntax
- fix corner case with comma operator
2022-09-29 12:18:04 +08:00
Alex Lam S.L
a570c00251 fix corner case in conditionals & if_return (#5685)
fixes #5684
2022-09-28 00:04:32 +08:00
Alex Lam S.L
3fa2086681 improve usability of mangle.properties (#5683)
fixes #5682
2022-09-27 13:52:58 +08:00
Alex Lam S.L
8e65413b99 fix corner cases in conditionals & if_return (#5680)
fixes #5679
2022-09-27 01:28:03 +08:00
Alex Lam S.L
8ca40070a4 workaround GitHub Actions quirks (#5678) 2022-09-27 00:16:40 +08:00
Alex Lam S.L
f9b811ce83 v3.17.2 2022-09-26 00:12:51 +08:00
Alex Lam S.L
9ac3879b06 fix corner case in conditionals (#5676) 2022-09-23 11:09:55 +08:00
Alex Lam S.L
37d3e4feaa fix corner case in if_return (#5675) 2022-09-22 23:27:06 +08:00
Alex Lam S.L
43ec350cd2 fix corner case in conditionals (#5674)
fixes #5673
2022-09-22 10:58:44 +08:00
Alex Lam S.L
63b04a687a minor tweaks (#5672) 2022-09-21 23:11:46 +08:00
Alex Lam S.L
9efa02afb6 fix corner case in assignments (#5671)
fixes #5670
2022-09-21 07:56:16 +08:00
Alex Lam S.L
3a6e58109e v3.17.1 2022-09-20 04:13:28 +08:00
Alex Lam S.L
5ac6ec5496 improve usability of --mangle-props (#5669) 2022-09-18 09:37:06 +08:00
Alex Lam S.L
eb22f0101e fix corner case in unused (#5668)
fixes #5663
2022-09-17 13:32:41 +08:00
Alex Lam S.L
e4bff315eb fix corner case in conditionals (#5667)
fixes #5666
2022-09-17 10:42:32 +08:00
Alex Lam S.L
001f6f9719 fix corner case in inline (#5664)
fixes #5662
2022-09-17 08:54:54 +08:00
Alex Lam S.L
e0b302d651 fix corner case in merge_vars (#5661)
fixes #5660
2022-09-14 23:36:54 +08:00
Alex Lam S.L
fa2511f71c tweak ufuzz job scheduling (#5659) 2022-09-11 04:05:21 +08:00
Alex Lam S.L
edf1bf1106 enhance varify (#5658) 2022-09-11 03:28:54 +08:00
Alex Lam S.L
88dfc49683 fix corner case in merge_vars (#5657)
fixes #5656
2022-09-10 04:14:33 +08:00
Alex Lam S.L
9dec612cd5 enhance inline (#5655)
- improve fix for #5653
2022-09-09 04:07:47 +08:00
Alex Lam S.L
02d966d914 fix corner case in hoist_props (#5654)
fixes #5653
2022-09-08 10:55:59 +08:00
Alex Lam S.L
5b5f6e329c fix corner case in ie (#5652)
fixes #5651
2022-09-08 10:49:40 +08:00
Alex Lam S.L
4e4a2f8ed3 fix corner case in if_return (#5650)
fixes #5649
2022-09-08 10:49:05 +08:00
Alex Lam S.L
32bd65a87f support ExtendScript parser quirks (#5648)
closes #1144
2022-09-07 02:28:34 +08:00
Alex Lam S.L
318206d41d suppress false positives in ufuzz (#5647) 2022-09-06 01:33:22 +08:00
Alex Lam S.L
535212c69e allow glob-style input for --in-situ (#5646)
closes #5645
2022-09-05 22:54:35 +08:00
Alex Lam S.L
1d42e9ad55 fix corner case in collapse_vars (#5644)
fixes #5643
2022-09-04 10:10:31 +08:00
Alex Lam S.L
78f354beb8 fix corner case in dead_code (#5642)
fixes #5641
2022-09-04 06:18:25 +08:00
Alex Lam S.L
e012f046bc tweak test cases (#5640) 2022-08-31 12:16:42 +08:00
Alex Lam S.L
f63b7b079d fix corner case in collapse_vars (#5639)
fixes #5638
2022-08-31 08:44:04 +08:00
Alex Lam S.L
d530f9332c enhance awaits (#5637) 2022-08-31 02:51:42 +08:00
Alex Lam S.L
10bc86ba10 enhance reduce_vars (#5636) 2022-08-30 16:00:43 +08:00
Alex Lam S.L
15b608f74c fix corner case in inline (#5635)
fixes #5634
2022-08-30 00:45:35 +08:00
Alex Lam S.L
7c52af0dec workaround quirks from npm (#5633) 2022-08-26 20:08:04 +08:00
Alex Lam S.L
cd97237c59 workaround quirks from GitHub Actions (#5632) 2022-08-26 15:16:03 +08:00
Alex Lam S.L
965e9767e5 workaround quirks from Node.js (#5631) 2022-08-26 06:25:44 +08:00
Alex Lam S.L
41a7000745 workaround quirks from GitHub Actions (#5630) 2022-08-26 02:35:53 +08:00
Alex Lam S.L
9cdc1ef6c2 fix corner case in unused (#5629)
fixes #5628
2022-08-25 05:01:12 +08:00
Alex Lam S.L
4db81065ee fix corner case in hoist_vars (#5627)
fixes #5626
2022-08-24 00:19:47 +08:00
Alex Lam S.L
4653e8aec0 improve diagnostics on top_retain & mangle.properties (#5622)
closes #5618
2022-08-19 02:32:21 +08:00
Alex Lam S.L
ac002b6338 fix corner case in reduce_vars (#5624)
fixes #5623
2022-08-19 02:31:48 +08:00
Alex Lam S.L
9eea3a673a provide diagnostic details on --mangle-props (#5621)
closes #5618
2022-08-17 22:22:30 +08:00
Alex Lam S.L
d6d2f5ced2 enhance reduce_vars (#5616)
closes #5614
2022-08-17 09:25:59 +08:00
Alex Lam S.L
887e086890 fix corner case in if_return (#5620)
fixes #5619
2022-08-17 09:10:33 +08:00
64 changed files with 3971 additions and 559 deletions

View File

@@ -3,7 +3,7 @@ Contributing
## Documentation
Every new feature and API change should be accompanied by a README additon.
Every new feature and API change should be accompanied by a README addition.
## Testing

View File

@@ -327,7 +327,7 @@ unquoted style (`o.foo`). Example:
// stuff.js
var o = {
"foo": 1,
bar: 3
bar: 3,
};
o.foo += o.bar;
console.log(o.foo);
@@ -339,6 +339,16 @@ $ uglifyjs stuff.js --mangle-props keep_quoted -c -m
var o={foo:1,o:3};o.foo+=o.o,console.log(o.foo);
```
If the minified output will be processed again by UglifyJS, consider specifying
`keep_quoted_props` so the same property names are preserved:
```bash
$ uglifyjs stuff.js --mangle-props keep_quoted -c -m -O keep_quoted_props
```
```javascript
var o={"foo":1,o:3};o.foo+=o.o,console.log(o.foo);
```
### Debugging property name mangling
You can also pass `--mangle-props debug` in order to mangle property names
@@ -636,7 +646,7 @@ to be `false` and all symbol names will be omitted.
- `bare_returns` (default: `false`) — support top level `return` statements
- `html5_comments` (default: `true`) — process HTML comment as workaround for
browsers which do not recognise `<script>` tags
browsers which do not recognize `<script>` tags
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` and support for top-level `await`.
@@ -743,7 +753,7 @@ to be `false` and all symbol names will be omitted.
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the
where the return value is discarded, to avoid the parentheses that the
code generator would insert.
- `objects` (default: `true`) — compact duplicate keys in object literals.
@@ -841,7 +851,7 @@ to be `false` and all symbol names will be omitted.
- `unused` (default: `true`) — drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`)
- `varify` (default: `true`) — convert block-scoped declaractions into `var`
- `varify` (default: `true`) — convert block-scoped declarations into `var`
whenever safe to do so
- `yields` (default: `true`) — apply optimizations to `yield` expressions
@@ -881,12 +891,15 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
### Mangle properties options
- `builtins` (default: `false`) — Use `true` to allow the mangling of builtin
DOM properties. Not recommended to override this setting.
- `builtins` (default: `false`) — Use `true` to allow the mangling of built-in
properties of JavaScript API. Not recommended to override this setting.
- `debug` (default: `false`) — Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `domprops` (default: `false`) — Use `true` to allow the mangling of properties
commonly found in Document Object Model. Not recommended to override this setting.
- `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function
arguments.
@@ -930,6 +943,9 @@ can pass additional arguments that control the code output:
}
```
- `extendscript` (default: `false`) — enable workarounds for Adobe ExtendScript
bugs
- `galio` (default: `false`) — enable workarounds for ANT Galio bugs
- `indent_level` (default: `4`) — indent by specified number of spaces or the
@@ -1446,3 +1462,17 @@ To allow for better optimizations, the compiler makes various assumptions:
// Actual: TypeError: invalid assignment to const 'f'
```
UglifyJS may modify the input which in turn may suppress those errors.
- Adobe ExtendScript will give incorrect results with the following:
```javascript
alert(true ? "PASS" : false ? "FAIL" : null);
// Expected: "PASS"
// Actual: "FAIL"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Adobe ExtendScript will give incorrect results with the following:
```javascript
alert(42 ? null ? "FAIL" : "PASS" : "FAIL");
// Expected: "PASS"
// Actual: SyntaxError: Expected: :
```
UglifyJS may modify the input which in turn may suppress those errors.

View File

@@ -238,17 +238,6 @@ if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot
[ "compress", "mangle" ].forEach(function(name) {
if (!(name in options)) options[name] = false;
});
if (options.mangle && options.mangle.properties) {
if (options.mangle.properties.domprops) {
delete options.mangle.properties.domprops;
} else {
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS.push_uniq(options.mangle.properties.reserved, name);
});
}
}
if (/^ast|spidermonkey$/.test(output)) {
if (typeof options.output != "object") options.output = {};
options.output.ast = true;
@@ -278,6 +267,8 @@ if (specified["self"]) {
if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
if (!options.wrap) options.wrap = "UglifyJS";
paths = UglifyJS.FILES;
} else if (paths.length) {
paths = simple_glob(paths);
}
if (specified["in-situ"]) {
if (output && output != "spidermonkey" || specified["reduce-test"] || specified["self"]) {
@@ -292,7 +283,7 @@ if (specified["in-situ"]) {
run();
});
} else if (paths.length) {
simple_glob(paths).forEach(function(name) {
paths.forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
@@ -491,33 +482,42 @@ function fatal(message) {
// A file glob function that only supports "*" and "?" wildcards in the basename.
// Example: "foo/bar/*baz??.*.js"
// Argument `glob` may be a string or an array of strings.
// Argument `paths` must be an array of strings.
// Returns an array of strings. Garbage in, garbage out.
function simple_glob(glob) {
if (Array.isArray(glob)) {
return [].concat.apply([], glob.map(simple_glob));
}
if (glob.match(/\*|\?/)) {
var dir = path.dirname(glob);
try {
var entries = fs.readdirSync(dir);
} catch (ex) {}
if (entries) {
var pattern = "^" + path.basename(glob)
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
.replace(/\*/g, "[^/\\\\]*")
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.sort().filter(function(name) {
return rx.test(name);
}).map(function(name) {
return path.join(dir, name);
});
if (results.length) return results;
function simple_glob(paths) {
return paths.reduce(function(paths, glob) {
if (/\*|\?/.test(glob)) {
var dir = path.dirname(glob);
try {
var entries = fs.readdirSync(dir).filter(function(name) {
try {
return fs.statSync(path.join(dir, name)).isFile();
} catch (ex) {
return false;
}
});
} catch (ex) {}
if (entries) {
var pattern = "^" + path.basename(glob)
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
.replace(/\*/g, "[^/\\\\]*")
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.filter(function(name) {
return rx.test(name);
}).sort().map(function(name) {
return path.join(dir, name);
});
if (results.length) {
[].push.apply(paths, results);
return paths;
}
}
}
}
return [ glob ];
paths.push(glob);
return paths;
}, []);
}
function read_file(path, default_value) {

View File

@@ -332,7 +332,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
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",
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any inner scopes",
functions: "[Dictionary/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Dictionary/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
@@ -1519,7 +1519,7 @@ var AST_New = DEFNODE("New", null, {
var AST_Sequence = DEFNODE("Sequence", "expressions", {
$documentation: "A sequence expression (comma-separated expressions)",
$propdoc: {
expressions: "[AST_Node*] array of expressions (at least two)"
expressions: "[AST_Node*] array of expressions (at least two)",
},
_equals: function(node) {
return all_equals(this.expressions, node.expressions);
@@ -1568,8 +1568,11 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression optional property termina
},
});
var AST_Dot = DEFNODE("Dot", null, {
var AST_Dot = DEFNODE("Dot", "quoted", {
$documentation: "A dotted property access expression",
$propdoc: {
quoted: "[boolean] whether property is transformed from a quoted string",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1618,7 +1621,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
$documentation: "Base class for unary expressions",
$propdoc: {
operator: "[string] the operator",
expression: "[AST_Node] expression that this unary operator applies to"
expression: "[AST_Node] expression that this unary operator applies to",
},
_equals: function(node) {
return this.operator == node.operator

File diff suppressed because it is too large Load Diff

View File

@@ -205,6 +205,7 @@ function minify(files, options) {
toplevel.mangle_names(options.mangle);
}
if (timings) timings.properties = Date.now();
if (quoted_props) reserve_quoted_keys(toplevel, quoted_props);
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
if (options.parse.expression) toplevel = toplevel.unwrap_expression();
if (timings) timings.output = Date.now();

View File

@@ -55,6 +55,7 @@ function OutputStream(options) {
beautify : false,
braces : false,
comments : false,
extendscript : false,
galio : false,
ie : false,
indent_level : 4,
@@ -75,7 +76,7 @@ function OutputStream(options) {
wrap_iife : false,
}, true);
// Convert comment option to RegExp if neccessary and set up comments filter
// Convert comment option to RegExp if necessary and set up comments filter
var comment_filter = return_false; // Default case, throw all comments away
if (options.comments) {
var comments = options.comments;
@@ -700,6 +701,7 @@ function OutputStream(options) {
if (p instanceof AST_Class) return true;
// (x++)[y]
// (typeof x).y
// https://github.com/mishoo/UglifyJS/issues/115
if (p instanceof AST_PropAccess) return p.expression === this;
// (~x)`foo`
if (p instanceof AST_Template) return p.tag === this;
@@ -875,7 +877,9 @@ function OutputStream(options) {
return needs_parens_assign_cond(this, output);
});
PARENS(AST_Conditional, function(output) {
return needs_parens_assign_cond(this, output);
return needs_parens_assign_cond(this, output)
// https://github.com/mishoo/UglifyJS/issues/1144
|| output.option("extendscript") && output.parent() instanceof AST_Conditional;
});
PARENS(AST_Yield, function(output) {
return needs_parens_assign_cond(this, output);
@@ -993,7 +997,7 @@ function OutputStream(options) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
} else {
parenthesize_for_noin(self.init, output, true);
parenthesize_for_no_in(self.init, output, true);
}
output.print(";");
output.space();
@@ -1409,7 +1413,7 @@ function OutputStream(options) {
print_braced(this, output);
});
function print_definitinos(type) {
function print_definitions(type) {
return function(output) {
var self = this;
output.print(type);
@@ -1422,15 +1426,15 @@ function OutputStream(options) {
if (!(p instanceof AST_IterationStatement && p.init === self)) output.semicolon();
};
}
DEFPRINT(AST_Const, print_definitinos("const"));
DEFPRINT(AST_Let, print_definitinos("let"));
DEFPRINT(AST_Var, print_definitinos("var"));
DEFPRINT(AST_Const, print_definitions("const"));
DEFPRINT(AST_Let, print_definitions("let"));
DEFPRINT(AST_Var, print_definitions("var"));
function parenthesize_for_noin(node, output, noin) {
function parenthesize_for_no_in(node, output, no_in) {
var parens = false;
// need to take some precautions here:
// https://github.com/mishoo/UglifyJS/issues/60
if (noin) node.walk(new TreeWalker(function(node) {
if (no_in) node.walk(new TreeWalker(function(node) {
if (parens) return true;
if (node instanceof AST_Binary && node.operator == "in") return parens = true;
if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true;
@@ -1446,8 +1450,8 @@ function OutputStream(options) {
output.print("=");
output.space();
var p = output.parent(1);
var noin = p instanceof AST_For || p instanceof AST_ForEnumeration;
parenthesize_for_noin(self.value, output, noin);
var no_in = p instanceof AST_For || p instanceof AST_ForEnumeration;
parenthesize_for_no_in(self.value, output, no_in);
}
});
@@ -1513,7 +1517,7 @@ function OutputStream(options) {
var expr = self.expression;
expr.print(output);
var prop = self.property;
if (output.option("ie") && RESERVED_WORDS[prop]) {
if (output.option("ie") && RESERVED_WORDS[prop] || self.quoted && output.option("keep_quoted_props")) {
if (self.optional) output.print("?.");
output.with_square(function() {
output.add_mapping(self.end);

View File

@@ -782,7 +782,7 @@ function parse($TEXT, options) {
else if (!optional && !can_insert_semicolon()) expect(";");
}
function parenthesised() {
function parenthesized() {
expect("(");
var exp = expression();
expect(")");
@@ -920,18 +920,18 @@ function parse($TEXT, options) {
next();
var body = in_loop(statement);
expect_token("keyword", "while");
var condition = parenthesised();
var condition = parenthesized();
semicolon(true);
return new AST_Do({
body : body,
condition : condition
condition : condition,
});
case "while":
next();
return new AST_While({
condition : parenthesised(),
body : in_loop(statement)
condition : parenthesized(),
body : in_loop(statement),
});
case "for":
@@ -959,15 +959,13 @@ function parse($TEXT, options) {
value = expression();
semicolon();
}
return new AST_Return({
value: value
});
return new AST_Return({ value: value });
case "switch":
next();
return new AST_Switch({
expression : parenthesised(),
body : in_loop(switch_body_)
expression : parenthesized(),
body : in_loop(switch_body_),
});
case "throw":
@@ -976,9 +974,7 @@ function parse($TEXT, options) {
croak("Illegal newline after 'throw'");
var value = expression();
semicolon();
return new AST_Throw({
value: value
});
return new AST_Throw({ value: value });
case "try":
next();
@@ -996,8 +992,8 @@ function parse($TEXT, options) {
}
next();
return new AST_With({
expression : parenthesised(),
body : statement()
expression : parenthesized(),
body : statement(),
});
}
}
@@ -1421,15 +1417,15 @@ function parse($TEXT, options) {
};
function if_() {
var cond = parenthesised(), body = statement(), belse = null;
var cond = parenthesized(), body = statement(), alt = null;
if (is("keyword", "else")) {
next();
belse = statement();
alt = statement();
}
return new AST_If({
condition : cond,
body : body,
alternative : belse
alternative : alt,
});
}
@@ -2171,9 +2167,9 @@ function parse($TEXT, options) {
token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
}
function as_symbol(type, noerror) {
function as_symbol(type, no_error) {
if (!is("name")) {
if (!noerror) croak("Name expected");
if (!no_error) croak("Name expected");
return null;
}
var sym = _make_symbol(type, S.token);
@@ -2409,20 +2405,20 @@ function parse($TEXT, options) {
return new ctor({ operator: op, expression: expr });
}
var expr_op = function(left, min_prec, no_in) {
var expr_op = function(left, min_precision, no_in) {
var op = is("operator") ? S.token.value : null;
if (op == "in" && no_in) op = null;
var prec = op != null ? PRECEDENCE[op] : null;
if (prec != null && prec > min_prec) {
var precision = op != null ? PRECEDENCE[op] : null;
if (precision != null && precision > min_precision) {
next();
var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in);
var right = expr_op(maybe_unary(no_in), op == "**" ? precision - 1 : precision, no_in);
return expr_op(new AST_Binary({
start : left.start,
left : left,
operator : op,
right : right,
end : right.end
}), min_prec, no_in);
end : right.end,
}), min_precision, no_in);
}
return left;
};

View File

@@ -124,10 +124,16 @@ function get_builtins() {
function reserve_quoted_keys(ast, reserved) {
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ClassProperty) {
if (node.start && node.start.quote) add(node.key);
} else if (node instanceof AST_ObjectProperty) {
if (node.start && node.start.quote) add(node.key);
if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else if (node.start && node.start.quote) {
add(node.key);
}
} else if (node instanceof AST_Dot) {
if (node.quoted) add(node.property);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
@@ -154,12 +160,16 @@ function mangle_properties(ast, options) {
builtins: false,
cache: null,
debug: false,
domprops: false,
keep_quoted: false,
regex: null,
reserved: null,
}, true);
var reserved = options.builtins ? new Dictionary() : get_builtins();
if (!options.domprops && typeof domprops !== "undefined") domprops.forEach(function(name) {
reserved.set(name, true);
});
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
reserved.set(name, true);
});
@@ -178,7 +188,7 @@ function mangle_properties(ast, options) {
var regex = options.regex;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
// note debug may be enabled as an empty string, which is falsy. Also treat passing 'true'
// the same as passing an empty string.
var debug = options.debug !== false;
var debug_suffix;
@@ -189,9 +199,7 @@ function mangle_properties(ast, options) {
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_Binary) {
if (node.operator == "in") addStrings(node.left, add);
} else if (node.TYPE == "Call") {
if (node.TYPE == "Call") {
var exp = node.expression;
if (exp instanceof AST_Dot) switch (exp.property) {
case "defineProperty":
@@ -208,14 +216,18 @@ function mangle_properties(ast, options) {
addStrings(node.args[0], add);
break;
}
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") add(node.key);
} else if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else {
add(node.key);
}
} else if (node instanceof AST_Dot) {
add(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") add(node.key);
if (is_lhs(node, this.parent())) add(node.property);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
if (is_lhs(node, this.parent())) addStrings(node.property, add);
}
}));
@@ -240,12 +252,16 @@ function mangle_properties(ast, options) {
mangleStrings(node.args[0]);
break;
}
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
mangleStrings(node.key);
} else {
node.key = mangle(node.key);
}
} else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_Sub) {
if (!options.keep_quoted) mangleStrings(node.property);
}
@@ -260,8 +276,14 @@ function mangle_properties(ast, options) {
}
function should_mangle(name) {
if (reserved.has(name)) return false;
if (regex && !regex.test(name)) return false;
if (reserved.has(name)) {
AST_Node.info("Preserving reserved property {this}", name);
return false;
}
if (regex && !regex.test(name)) {
AST_Node.info("Preserving excluded property {this}", name);
return false;
}
return cache.has(name) || names_to_mangle.has(name);
}
@@ -286,12 +308,16 @@ function mangle_properties(ast, options) {
if (/^#/.test(name)) mangled = "#" + mangled;
cache.set(name, mangled);
}
AST_Node.info("Mapping property {name} to {mangled}", {
mangled: mangled,
name: name,
});
return mangled;
}
function mangleStrings(node) {
if (node instanceof AST_Sequence) {
mangleStrings(node.expressions.tail_node());
mangleStrings(node.tail_node());
} else if (node instanceof AST_String) {
node.value = mangle(node.value);
} else if (node instanceof AST_Conditional) {

View File

@@ -369,8 +369,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// pass 3: fix up any scoping issue with IE8
if (options.ie) self.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolCatch) {
var scope = node.thedef.defun;
if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
var def = node.thedef;
var scope = def.defun;
if (def.name != "arguments" && scope.name instanceof AST_SymbolLambda && scope.name.name == def.name) {
scope = scope.parent_scope.resolve();
}
redefine(node, scope);

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.17.0",
"version": "3.17.4",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -126,6 +126,17 @@ function parse_test(file) {
croak(node);
}
var name = node.left.name;
assert.ok([
"beautify",
"expression",
"mangle",
"options",
"rename",
].indexOf(name) >= 0, tmpl("Unsupported setting {name} [{line},{col}]", {
name: name,
line: node.start.line,
col: node.start.col,
}));
test[name] = evaluate(node.right);
return true;
}
@@ -271,7 +282,9 @@ function test_case(test) {
expect = test.expect_exact;
}
var input = to_toplevel(test.input, test.mangle, test.expression);
var input_code = make_code(input, {}, test.expression);
var input_code = make_code(input, {
keep_quoted_props: true,
}, test.expression);
var input_formatted = make_code(test.input, {
annotations: true,
beautify: true,
@@ -307,8 +320,9 @@ function test_case(test) {
warnings_emitted.push(text);
}, /"INFO: /.test(expected_warnings));
}
var quoted_props;
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var quoted_props = test.mangle.properties.reserved;
quoted_props = test.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
@@ -323,6 +337,7 @@ function test_case(test) {
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (quoted_props) U.reserve_quoted_keys(input, quoted_props);
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
}
var output_code = make_code(output, output_options, test.expression);
@@ -459,6 +474,7 @@ function to_toplevel(input, mangle_options, expression) {
var tokens = [];
input.walk(new U.TreeWalker(function(node) {
if (U.push_uniq(tokens, node.start)) node.start.line -= offset;
if (U.push_uniq(tokens, node.end)) node.end.line -= offset;
}));
var toplevel;
if (!expression) {

View File

@@ -668,6 +668,28 @@ single_use_recursive: {
node_version: ">=4"
}
inline_iife_within_arrow: {
options = {
arrows: true,
inline: true,
}
input: {
var f = () => console.log(function(a) {
return Math.ceil(a);
}(Math.random()));
f();
}
expect: {
var f = () => {
return console.log((a = Math.random(), Math.ceil(a)));
var a;
};
f();
}
expect_stdout: "1"
node_version: ">=4"
}
issue_4388: {
options = {
inline: true,
@@ -1212,3 +1234,28 @@ issue_5495: {
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5653: {
options = {
arrows: true,
hoist_props: true,
passes: 2,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
console.log((a => {
a = { p: console };
return a++;
})());
}
expect: {
console.log((a => {
return console, +{};
})());
}
expect_stdout: "NaN"
node_version: ">=4"
}

View File

@@ -290,6 +290,45 @@ increment_decrement_2: {
expect_stdout: "42"
}
lazily_chained_assignments: {
options = {
assignments: true,
collapse_vars: true,
conditionals: true,
unused: true,
}
input: {
function f(a) {
if (a = console.log("foo"))
a = console.log("bar");
return a;
}
function g(b) {
if (b = console.log("baz"))
;
else
b = console.log("moo");
return b;
}
console.log(f(), g());
}
expect: {
function f(a) {
return console.log("foo") && console.log("bar");
}
function g(b) {
return console.log("baz") || console.log("moo");
}
console.log(f(), g());
}
expect_stdout: [
"foo",
"baz",
"moo",
"undefined undefined",
]
}
issue_3375_1: {
options = {
assignments: true,
@@ -803,3 +842,23 @@ issue_4924_2: {
expect_stdout: "PASS"
node_version: ">=15"
}
issue_5670: {
options = {
assignments: true,
evaluate: true,
reduce_vars: true,
}
input: {
(function(a, b) {
a && a && (a = b += "") || console.log("PASS");
})();
}
expect: {
(function(a, b) {
a = a,
console.log("PASS");
})();
}
expect_stdout: "PASS"
}

View File

@@ -529,6 +529,7 @@ inline_block_await: {
inline_block_await_async: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2747,6 +2748,7 @@ issue_5177: {
issue_5250: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2855,6 +2857,7 @@ issue_5298: {
issue_5305_1: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2888,6 +2891,7 @@ issue_5305_1: {
issue_5305_2: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -3078,6 +3082,7 @@ issue_5506: {
issue_5528_1: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -3113,6 +3118,7 @@ issue_5528_1: {
issue_5528_2: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -3148,6 +3154,7 @@ issue_5528_2: {
issue_5528_3: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -3188,6 +3195,7 @@ issue_5528_3: {
issue_5528_4: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -3229,3 +3237,364 @@ issue_5528_4: {
]
node_version: ">=8"
}
issue_5634_1: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_1_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_2: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_2_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_3: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_3_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5692_1: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=10"
}
issue_5692_2: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
for (var k of []);
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}

View File

@@ -80,6 +80,25 @@ de_morgan_1c: {
expect_stdout: "true"
}
de_morgan_1d: {
options = {
booleans: true,
}
input: {
function f(a) {
return (a = false) || a;
}
console.log(f(null), f(42));
}
expect: {
function f(a) {
return a = !1;
}
console.log(f(null), f(42));
}
expect_stdout: "false false"
}
de_morgan_2a: {
options = {
booleans: true,
@@ -181,6 +200,31 @@ de_morgan_2d: {
]
}
de_morgan_2e: {
options = {
booleans: true,
conditionals: true,
}
input: {
function f(a, b) {
return (a && b) && b;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a && b;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"undefined {}",
]
}
de_morgan_3a: {
options = {
booleans: true,
@@ -786,3 +830,37 @@ issue_5469: {
}
expect_stdout: "undefined"
}
issue_5694_1: {
options = {
booleans: true,
conditionals: true,
}
input: {
var Infinity;
// Node.js v0.12~6 (vm): 42
console.log((Infinity = 42) && Infinity);
}
expect: {
var Infinity;
console.log((Infinity = 42) && Infinity);
}
expect_stdout: true
}
issue_5694_2: {
options = {
booleans: true,
conditionals: true,
}
input: {
var undefined;
// Node.js v0.12~6 (vm): NaN
console.log(("foo", ++undefined) || undefined);
}
expect: {
var undefined;
console.log(("foo", ++undefined) || undefined);
}
expect_stdout: true
}

View File

@@ -599,6 +599,7 @@ drop_extends: {
inline: true,
passes: 2,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -921,6 +922,7 @@ single_use_3: {
single_use_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -1503,6 +1505,218 @@ keep_instanceof_3: {
node_version: ">=4"
}
keep_field_reference_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
class A {
p = f;
}
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f() {}
class A {
p = f;
}
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
var A = class {
p = f;
};
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f() {}
var A = class {
p = f;
};
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
class B {
p = A;
}
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
class A {}
class B {
p = A;
}
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var A = class {};
var B = class {
p = A;
};
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
var A = class {};
var B = class {
p = A;
};
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
class A {
static P = f;
}
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
class A {
static P = function() {};
}
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
var A = class {
static P = f;
};
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
var A = class {
static P = function() {};
};
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
class B {
static P = A;
}
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
class B {
static P = class {};
}
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var A = class {};
var B = class {
static P = A;
};
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
var B = class {
static P = class {};
};
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
issue_805_1: {
options = {
inline: true,
@@ -2164,6 +2378,7 @@ issue_4829_2: {
mangle_properties: {
mangle = {
properties: {
domprops: true,
keep_quoted: true,
},
}
@@ -2200,6 +2415,14 @@ mangle_properties: {
console.log(A.s, new A().e);
}
expect_stdout: "PASS 42"
expect_warnings: [
"INFO: Preserving reserved property q",
"INFO: Mapping property #P to #t",
"INFO: Mapping property Q to s",
"INFO: Mapping property #p to #i",
"INFO: Mapping property r to e",
"INFO: Preserving reserved property log",
]
node_version: ">=14.6"
}
@@ -2304,6 +2527,7 @@ issue_4962_1: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2335,6 +2559,7 @@ issue_4962_1_strict: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2362,6 +2587,7 @@ issue_4962_1_strict_direct: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2393,6 +2619,7 @@ issue_4962_2: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2424,6 +2651,7 @@ issue_4962_2_strict: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2452,6 +2680,7 @@ issue_4962_2_strict_direct: {
options = {
ie: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2486,6 +2715,7 @@ issue_4962_2_strict_direct_inline: {
ie: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2869,6 +3099,7 @@ issue_5053_4: {
issue_5082_1: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2901,6 +3132,7 @@ issue_5082_1: {
issue_5082_1_strict: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2934,6 +3166,7 @@ issue_5082_2: {
options = {
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -2967,6 +3200,7 @@ issue_5082_2_static: {
options = {
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -3578,3 +3812,92 @@ issue_5531_3: {
expect_stdout: "foo"
node_version: ">=16"
}
issue_5662: {
options = {
inline: true,
reduce_vars: true,
}
input: {
console.log(new (function() {
var g = function(a) {
return a;
};
return class {
h(b) {
return g(b);
}
};
}())().h("PASS"));
}
expect: {
console.log(new (function() {
var g = function(a) {
return a;
};
return class {
h(b) {
return g(b);
}
};
}())().h("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5682_class_key: {
mangle = {
properties: true,
}
input: {
"use strict";
function f(a) {
return "foo" in a;
}
class A {
foo() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f(o) {
return "o" in o;
}
class A {
o() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5682_class_key_computed: {
mangle = {
properties: true,
}
input: {
"use strict";
function f(a) {
return "foo" in a;
}
class A {
["foo"]() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f(o) {
return "o" in o;
}
class A {
["o"]() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -9321,12 +9321,11 @@ issue_4874: {
})(a = 42);
}
expect: {
var a;
null;
(function(b) {
for (var c in a && a[console.log("PASS")])
for (var c in 42, 42[console.log("PASS")])
console;
})(a = 42);
})();
}
expect_stdout: "PASS"
}
@@ -10001,3 +10000,124 @@ issue_5568: {
}
expect_stdout: "PASS"
}
issue_5638_1: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a;
console;
a = [ 42 ];
console || FAIL(a);
console.log(a++);
}
expect: {
var a;
console;
a = [ 42 ];
console || FAIL(a);
console.log(a++);
}
expect_stdout: "42"
}
issue_5638_2: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a;
console;
a = [ 6 ];
console || FAIL(a);
console.log(a *= 7);
}
expect: {
var a;
console;
a = [ 6 ];
console || FAIL(a);
console.log(a *= 7);
}
expect_stdout: "42"
}
issue_5638_3: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var a = { foo: 42 }, b;
for (var k in a) {
b = a[k];
log(k || b, b++);
}
}
expect: {
var log = console.log;
var a = { foo: 42 }, b;
for (var k in a) {
b = a[k];
log(k || b, b++);
}
}
expect_stdout: "foo 42"
}
issue_5638_4: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var a = { foo: 6 }, b;
for (var k in a) {
b = a[k];
log(k || b, b *= 7);
}
}
expect: {
var log = console.log;
var a = { foo: 6 }, b;
for (var k in a) {
b = a[k];
log(k || b, b *= 7);
}
}
expect_stdout: "foo 42"
}
issue_5643: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 3, b;
a *= 7;
b = !!this;
console || console.log(b);
console.log(a * ++b);
}
expect: {
var a = 3, b;
a *= 7;
b = !!this;
console || console.log(b);
console.log(a * ++b);
}
expect_stdout: "42"
}

View File

@@ -275,6 +275,7 @@ issue_2857_3: {
issue_2857_4: {
options = {
comparisons: true,
conditionals: true,
}
input: {
function f(a, p) {
@@ -305,6 +306,7 @@ issue_2857_4: {
issue_2857_5: {
options = {
comparisons: true,
conditionals: true,
}
input: {
function f(a, p) {
@@ -528,6 +530,7 @@ nullish_assign: {
nullish_chain: {
options = {
comparisons: true,
conditionals: true,
}
input: {
var a;

View File

@@ -12,7 +12,7 @@ concat_1: {
var e = 1 + x() + 2 + "X" + 3 + "boo";
// be careful with concatentation with "\0" with octal-looking strings.
// be careful with concatenation with "\0" with octal-looking strings.
var f = "\0" + 360 + "\0" + 8 + "\0";
}
expect: {
@@ -273,6 +273,23 @@ concat_9: {
expect_stdout: true
}
concat_sequence: {
options = {
collapse_vars: true,
strings: true,
toplevel: true,
unused: true,
}
input: {
var a;
console.log(12 + (a = null, "34" + a));
}
expect: {
console.log(12 + "34" + null);
}
expect_stdout: "1234null"
}
issue_3689: {
options = {
strings: true,

View File

@@ -278,6 +278,36 @@ merge_tail_2: {
]
}
merge_tail_3: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
if (b = a.shift())
console.log(b);
else {
if (b = a.shift())
while (console.log("foo"));
console.log(b);
}
})([ false, "bar" ]);
}
expect: {
(function(a, b) {
if (!(b = a.shift()) && (b = a.shift()))
while (console.log("foo"));
console.log(b);
})([ false, "bar" ]);
}
expect_stdout: [
"foo",
"bar",
]
}
merge_tail_sequence_1: {
options = {
conditionals: true,
@@ -368,6 +398,39 @@ merge_tail_sequence_2: {
]
}
merge_tail_sequence_3: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
if (b = a.shift())
console.log("foo"),
console.log(b);
else {
if (b = a.shift())
while (console.log("bar"));
console.log(b);
}
})([ false, "baz" ]);
}
expect: {
(function(a, b) {
if (b = a.shift())
console.log("foo");
else if (b = a.shift())
while (console.log("bar"));
console.log(b);
})([ false, "baz" ]);
}
expect_stdout: [
"bar",
"baz",
]
}
cond_1: {
options = {
conditionals: true,
@@ -1176,6 +1239,52 @@ trivial_boolean_ternary_expressions : {
}
}
extendscript_1: {
beautify = {
extendscript: true,
}
input: {
var alert = console.log;
function f(a, b) {
return a ? b ? "foo" : "bar" : "baz";
}
alert(f());
alert(f(42));
alert(f(null, true));
alert(f([], {}));
}
expect_exact: 'var alert=console.log;function f(a,b){return a?(b?"foo":"bar"):"baz"}alert(f());alert(f(42));alert(f(null,true));alert(f([],{}));'
expect_stdout: [
"baz",
"bar",
"baz",
"foo",
]
}
extendscript_2: {
beautify = {
extendscript: true,
}
input: {
var alert = console.log;
function f(a, b) {
return a ? "foo" : b ? "bar" : "baz";
}
alert(f());
alert(f(42));
alert(f(null, true));
alert(f([], {}));
}
expect_exact: 'var alert=console.log;function f(a,b){return a?"foo":(b?"bar":"baz")}alert(f());alert(f(42));alert(f(null,true));alert(f([],{}));'
expect_stdout: [
"baz",
"foo",
"bar",
"foo",
]
}
issue_1154: {
options = {
booleans: true,
@@ -2832,3 +2941,130 @@ issue_5546_3: {
}
expect_stdout: "PASS"
}
issue_5666_1: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a;
(function() {
var b = a;
a ? a = b : (b++, a = b);
})();
console.log(a);
}
expect: {
var a;
(function() {
var b = a;
a = (a ? 0 : b++, b);
})();
console.log(a);
}
expect_stdout: "NaN"
}
issue_5666_2: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "foo";
(function() {
var b = a;
a ? (b++, a = b) : a = b;
})();
console.log(a);
}
expect: {
var a = "foo";
(function() {
var b = a;
a = (a ? b++ : 0, b);
})();
console.log(a);
}
expect_stdout: "NaN"
}
issue_5673_1: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b ? c : (c = a) && c);
}());
}
expect: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b || (c = a)) && c;
}());
}
expect_stdout: "PASS"
}
issue_5673_2: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
console.log(function(b) {
return (b = a) ? b : (b = a) && b;
}());
}
expect: {
var a = "PASS";
console.log(function(b) {
return a || (b = a) && b;
}());
}
expect_stdout: "PASS"
}
issue_5694: {
options = {
conditionals: true,
}
input: {
FORCE_EXEC = "async()=>{}";
var a = "foo";
// Node.js v0.12~6 (vm): foo
console.log((NaN = a) ? NaN : 42);
}
expect: {
FORCE_EXEC = "async()=>{}";
var a = "foo";
console.log((NaN = a) ? NaN : 42);
}
expect_stdout: "NaN"
}
issue_5712: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
}
input: {
var a = 0;
a || (++a).toString() && a && console.log("PASS");
}
expect: {
var a = 0;
a || (++a).toString() && a && console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -2144,3 +2144,63 @@ issue_5591: {
]
node_version: ">=4"
}
issue_5656: {
options = {
collapse_vars: true,
merge_vars: true,
}
input: {
console.log(function(a) {
var b = a;
b++;
{
const a = b;
}
}());
}
expect: {
console.log(function(a) {
var b = a;
{
const a = ++b;
}
}());
}
expect_stdout: true
}
issue_5660: {
options = {
merge_vars: true,
side_effects: true,
}
input: {
function f() {
try {
a;
var b;
return b;
} catch (e) {
var a = "FAIL";
const b = null;
return a;
}
}
console.log(f());
}
expect: {
function f() {
try {
var b;
return b;
} catch (e) {
var a = "FAIL";
const b = null;
return a;
}
}
console.log(f());
}
expect_stdout: true
}

View File

@@ -1485,8 +1485,6 @@ self_assignments_5: {
}
expect: {
var i = 0, l = [ "FAIL", "PASS" ];
l[0];
l[0];
l[0] = l[1];
console.log(l[0], 2);
}
@@ -1707,3 +1705,28 @@ issue_5506: {
"bar",
]
}
issue_5641: {
options = {
collapse_vars: true,
conditionals: true,
dead_code: true,
}
input: {
function f(a) {
if (a || b) {
var b = "PASS", c = b && console.log(b);
} else
var d = a || b;
}
f(42);
}
expect: {
function f(a) {
var b, c, d;
(a || b) && (b = "PASS") && console.log(b);
}
f(42);
}
expect_stdout: "PASS"
}

View File

@@ -668,6 +668,8 @@ drop_fargs: {
hoist_vars: {
options = {
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
var a = "PASS";
@@ -675,8 +677,7 @@ hoist_vars: {
console.log(a, b);
}
expect: {
var a = "PASS";
var [ b = 42 ] = [];
var a = "PASS", [ b = 42 ] = [];
console.log(a, b);
}
expect_stdout: "PASS 42"
@@ -2504,7 +2505,7 @@ issue_5463: {
var a, b, b;
console.log("PASS") && (
b = a = void 0,
b = [a = FAIL] = a && a
b = [a = FAIL] = a
);
}
expect_stdout: "PASS"
@@ -2712,7 +2713,7 @@ issue_5533_2_drop_fargs: {
try {
(function() {
for (;;) {
var [ [] = [] ] = [];
var [ [ , ] = [] ] = [];
throw "PASS";
}
})();
@@ -3035,10 +3036,36 @@ issue_5566_5: {
(function(a, f = function() {
return a;
}) {
var b, a = "foo";
var a, b;
a = "foo";
console.log(a, f());
})("bar");
}
expect_stdout: "foo bar"
node_version: ">=6"
}
issue_5651: {
options = {
ie: true,
unused: true,
}
input: {
console.log(function arguments(a = "FAIL") {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}());
}
expect: {
console.log(function arguments(a = "FAIL") {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}());
}
expect_stdout: true
node_version: ">=6"
}

View File

@@ -1306,7 +1306,7 @@ keep_reference: {
}
expect: {
var a = [ {}, 42 ];
var [ b ] = a;
var b = a[0];
console.log(a[0] === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
@@ -1652,6 +1652,8 @@ fn_name_unused: {
hoist_vars: {
options = {
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
var a = "PASS";
@@ -1659,8 +1661,7 @@ hoist_vars: {
console.log(a, b);
}
expect: {
var a = "PASS";
var [ b ] = [ 42 ];
var a = "PASS", b = [ 42 ][0];
console.log(a, b);
}
expect_stdout: "PASS 42"
@@ -1736,6 +1737,23 @@ singleton_side_effects: {
node_version: ">=6"
}
mangle_properties: {
mangle = {
properties: {
domprops: true,
},
}
input: {
function f({ p: a }) {
return a;
}
console.log(f({ p: "PASS" }));
}
expect_exact: 'function f({n}){return n}console.log(f({n:"PASS"}));'
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4280: {
options = {
evaluate: true,
@@ -3843,3 +3861,28 @@ issue_5573: {
]
node_version: ">=6"
}
issue_5651: {
options = {
ie: true,
unused: true,
}
input: {
console.log(function arguments({}) {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}("PASS"));
}
expect: {
console.log(function arguments({}) {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}("PASS"));
}
expect_stdout: true
node_version: ">=6"
}

View File

@@ -409,6 +409,15 @@ drop_toplevel_retain: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_retain_array: {
@@ -442,6 +451,15 @@ drop_toplevel_retain_array: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_retain_regex: {
@@ -471,6 +489,15 @@ drop_toplevel_retain_regex: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_all_retain: {
@@ -501,6 +528,15 @@ drop_toplevel_all_retain: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_funcs_retain: {
@@ -532,6 +568,12 @@ drop_toplevel_funcs_retain: {
function g() {}
console.log(b = 3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_vars_retain: {
@@ -564,6 +606,13 @@ drop_toplevel_vars_retain: {
function h() {}
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
]
}
drop_toplevel_keep_assign: {
@@ -1829,7 +1878,7 @@ issue_2846: {
var c = function(a, b) {
a = 0;
b && b(a);
return a++;
return +a;
}();
console.log(c);
}
@@ -2927,14 +2976,12 @@ issue_4025: {
console.log(a, b, d);
}
expect: {
var c = 0;
try {
console.log(c);
console.log(0);
} finally {
var d = c + 1;
c = 0;
0;
}
console.log(1, 1, d);
console.log(1, 1, 1);
}
expect_stdout: [
"0",
@@ -3647,7 +3694,7 @@ issue_5224: {
(function() {
var a = "FAIL 1";
null;
a = console.log(a);
console.log(a);
})(function() {
console.log(1 / 0);
a;

View File

@@ -560,3 +560,23 @@ issue_5444: {
export var a = console;
}
}
issue_5628: {
options = {
unused: true,
}
input: {
var a;
export default function f() {
for (a in 42);
}
console.log(a);
}
expect: {
var a;
export default function f() {
for (a in 42);
}
console.log(a);
}
}

View File

@@ -8719,3 +8719,24 @@ single_use_inline_collision: {
}
expect_stdout: "PASS"
}
issue_5692: {
options = {
inline: true,
}
input: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect_stdout: "PASS"
}

View File

@@ -462,6 +462,11 @@ issue_2473_1: {
var x = {};
var y = [];
}
expect_warnings: [
"INFO: Retaining variable x",
"INFO: Retaining variable y",
"WARN: Dropping unused variable z [test/compress/hoist_props.js:3,12]",
]
}
issue_2473_2: {
@@ -484,6 +489,11 @@ issue_2473_2: {
var x = {};
var y = [];
}
expect_warnings: [
"INFO: Retaining variable x",
"INFO: Retaining variable y",
"WARN: Dropping unused variable z [test/compress/hoist_props.js:3,12]",
]
}
issue_2473_3: {
@@ -509,6 +519,9 @@ issue_2473_3: {
console.log(o.a, o.b);
}
expect_stdout: "1 2"
expect_warnings: [
"INFO: Retaining variable o",
]
}
issue_2473_4: {
@@ -535,6 +548,9 @@ issue_2473_4: {
})();
}
expect_stdout: "1 2"
expect_warnings: [
"INFO: Dropping unused variable o [test/compress/hoist_props.js:2,16]",
]
}
issue_2508_1: {

View File

@@ -2,6 +2,8 @@ statements: {
options = {
hoist_funs: false,
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
function f() {
@@ -25,6 +27,8 @@ statements_funs: {
options = {
hoist_funs: true,
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
function f() {
@@ -48,6 +52,8 @@ sequences: {
options = {
hoist_funs: false,
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
function f() {
@@ -71,6 +77,8 @@ sequences_funs: {
options = {
hoist_funs: true,
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
function f() {
@@ -108,7 +116,8 @@ catch_var: {
console.log(a);
}
expect: {
var a = "PASS";
a = "PASS";
var a;
console.log(a);
}
expect_stdout: "PASS"
@@ -118,6 +127,8 @@ issue_2295: {
options = {
collapse_vars: true,
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
function foo(o) {
@@ -139,6 +150,7 @@ issue_4487_1: {
options = {
functions: true,
hoist_vars: true,
join_vars: true,
keep_fnames: true,
reduce_vars: true,
toplevel: true,
@@ -163,6 +175,7 @@ issue_4487_2: {
options = {
functions: true,
hoist_vars: true,
join_vars: true,
keep_fnames: true,
passes: 2,
reduce_vars: true,
@@ -188,6 +201,7 @@ issue_4487_3: {
options = {
functions: true,
hoist_vars: true,
join_vars: true,
keep_fnames: true,
passes: 3,
reduce_vars: true,
@@ -248,8 +262,7 @@ issue_4517: {
}
expect: {
console.log(function() {
var a = 2;
return (A = a) + typeof !1;
return (A = 2) + typeof !1;
}());
}
expect_stdout: "2boolean"
@@ -260,6 +273,7 @@ issue_4736: {
collapse_vars: true,
evaluate: true,
hoist_vars: true,
join_vars: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
@@ -279,7 +293,7 @@ issue_4736: {
expect: {
(function() {
(function() {
0,
0;
console.log(1 << 30);
})();
})();
@@ -291,6 +305,7 @@ issue_4839: {
options = {
evaluate: true,
hoist_vars: true,
join_vars: true,
keep_fargs: false,
reduce_vars: true,
toplevel: true,
@@ -317,6 +332,7 @@ issue_4859: {
options = {
evaluate: true,
hoist_vars: true,
join_vars: true,
keep_infinity: true,
merge_vars: true,
reduce_vars: true,
@@ -441,7 +457,7 @@ issue_4898: {
expect_stdout: "PASS"
}
issue_5187: {
issue_5187_1: {
options = {
hoist_props: true,
hoist_vars: true,
@@ -459,6 +475,37 @@ issue_5187: {
}
f();
}
expect: {
(function() {
var a, b;
a = 42;
do {
b = { 0: a++ };
} while (console.log(b[b ^= 0]));
})();
}
expect_stdout: "42"
}
issue_5187_2: {
options = {
hoist_props: true,
hoist_vars: true,
join_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;
@@ -547,9 +594,9 @@ issue_5411_1: {
console.log(b);
}
expect: {
var b, c, a = "PASS";
var a, b, c;
b++;
b = a;
b = a = "PASS";
c = c && c[b];
console.log(b);
}
@@ -577,7 +624,7 @@ issue_5411_2: {
var b, c;
b++;
b = "PASS",
c = c && c[b];
c;
console.log(b);
}
expect_stdout: "PASS"
@@ -596,6 +643,30 @@ issue_5411_3: {
var a = A = a;
console.log(A);
}
expect: {
var a;
a = console;
a = A = ++a;
console.log(A);
}
expect_stdout: "NaN"
}
issue_5411_4: {
options = {
collapse_vars: true,
hoist_vars: true,
join_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = console;
a++;
var a = A = a;
console.log(A);
}
expect: {
var a = console;
a = A = ++a;
@@ -603,3 +674,130 @@ issue_5411_3: {
}
expect_stdout: "NaN"
}
issue_5626: {
options = {
conditionals: true,
evaluate: true,
hoist_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = function() {
return console.log(arguments[0]), 42;
}("PASS") ? null : "foo";
for (var b in a)
FAIL;
}
expect: {
(function() {
console.log(arguments[0]);
}("PASS"));
for (var b in null)
FAIL;
}
expect_stdout: "PASS"
}
issue_5638_1: {
options = {
collapse_vars: true,
hoist_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = "FAIL";
var a = [ 42 ];
console || FAIL(a);
console.log(a++);
}
expect: {
var a;
a = "FAIL";
a = [ 42 ];
console || FAIL(a);
console.log(a++);
}
expect_stdout: "42"
}
issue_5638_2: {
options = {
collapse_vars: true,
hoist_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = "FAIL";
var a = [ 6 ];
console || FAIL(a);
console.log(a *= 7);
}
expect: {
var a;
a = "FAIL";
a = [ 6 ];
console || FAIL(a);
console.log(a *= 7);
}
expect_stdout: "42"
}
issue_5638_3: {
options = {
collapse_vars: true,
hoist_vars: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var o = { foo: 42 };
for (var k in o) {
var v = o[k];
log(k || v, v++);
}
}
expect: {
var log, o, k, v;
log = console.log;
for (k in o = { foo: 42 }) {
v = o[k];
log(k || v, v++);
}
}
expect_stdout: "foo 42"
}
issue_5638_4: {
options = {
collapse_vars: true,
hoist_vars: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var o = { foo: 6 };
for (var k in o) {
var v = o[k];
log(k || v, v *= 7);
}
}
expect: {
var log, o, k, v;
log = console.log;
for (k in o = { foo: 6 }) {
v = o[k];
log(k || v, v *= 7);
}
}
expect_stdout: "foo 42"
}

View File

@@ -525,7 +525,7 @@ if_var_return_2: {
}
}
if_var_retrn_3: {
if_var_return_3: {
options = {
conditionals: true,
if_return: true,
@@ -1834,6 +1834,63 @@ switch_return_5: {
]
}
merged_references_1: {
options = {
if_return: true,
reduce_vars: true,
unused: true,
}
input: {
var a, b = "PASS";
console.log(function(c) {
if (c = b)
return a || c;
c = FAIL;
return a || c;
}());
}
expect: {
var a, b = "PASS";
console.log(function(c) {
if (c = b);
else
c = FAIL;
return a || c;
}());
}
expect_stdout: "PASS"
}
merged_references_2: {
options = {
if_return: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
A = "PASS";
var a;
console.log(function(b) {
if (a = b)
return console && a;
a = FAIL;
return console && a;
}(A));
}
expect: {
A = "PASS";
var a;
console.log(function(b) {
if (a = b);
else
a = FAIL;
return console && a;
}(A));
}
expect_stdout: "PASS"
}
issue_5583: {
options = {
conditionals: true,
@@ -2305,3 +2362,121 @@ issue_5597: {
}
expect_stdout: "PASS"
}
issue_5619_1: {
options = {
if_return: true,
}
input: {
console.log(function() {
if (console)
if (console)
return "PASS";
var a = FAIL;
return "PASS";
}());
}
expect: {
console.log(function() {
if (console)
if (console)
return "PASS";
var a = FAIL;
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_5619_2: {
options = {
dead_code: true,
if_return: true,
loops: true,
}
input: {
console.log(function() {
if (console)
while (console)
return "PASS";
var a = FAIL;
return "PASS";
}());
}
expect: {
console.log(function() {
if (console) {
if (console)
return "PASS";
}
var a = FAIL;
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_5649: {
options = {
if_return: true,
}
input: {
console.log(function() {
try {
throw new Error("FAIL");
} catch (e) {
return "PASS";
}
throw new Error("FAIL");
}());
}
expect: {
console.log(function() {
try {
throw new Error("FAIL");
} catch (e) {
return "PASS";
}
throw new Error("FAIL");
}());
}
expect_stdout: "PASS"
}
issue_5688: {
options = {
conditionals: true,
if_return: true,
}
input: {
L: do {
switch (console) {
default:
if (console)
break;
if (FAIL_1)
;
else
break L;
break;
case 42:
FAIL_2;
}
} while (console.log("PASS"));
}
expect: {
L: do {
switch (console) {
default:
if (console)
break;
if (FAIL_1)
break;
break L;
case 42:
FAIL_2;
}
} while (console.log("PASS"));
}
expect_stdout: "PASS"
}

View File

@@ -140,12 +140,12 @@ mangle: {
}
input: {
import foo, { bar } from "baz";
consoe.log(moo);
console.log(moo);
import * as moo from "moz";
}
expect: {
import o, { bar as m } from "baz";
consoe.log(r);
console.log(r);
import * as r from "moz";
}
}
@@ -157,12 +157,12 @@ rename_mangle: {
}
input: {
import foo, { bar } from "baz";
consoe.log(moo);
console.log(moo);
import * as moo from "moz";
}
expect: {
import o, { bar as m } from "baz";
consoe.log(r);
console.log(r);
import * as r from "moz";
}
}

View File

@@ -1,6 +1,7 @@
issue_1321_no_debug: {
mangle = {
properties: {
domprops: true,
keep_quoted: true,
},
}
@@ -23,6 +24,7 @@ issue_1321_debug: {
mangle = {
properties: {
debug: "",
domprops: true,
keep_quoted: true,
},
}
@@ -44,6 +46,7 @@ issue_1321_debug: {
issue_1321_with_quoted: {
mangle = {
properties: {
domprops: true,
keep_quoted: false,
},
}

View File

@@ -1,5 +1,5 @@
/**
* There was an incorrect sort behaviour documented in issue #143:
* There was an incorrect sort behavior documented in issue #143:
* (x = f(…)) <= x → x >= (x = f(…))
*
* For example, let the equation be:
@@ -12,37 +12,54 @@
* a >= (a = parseInt('100')) → 99 >= 100 → false
*/
tranformation_sort_order_equal: {
transformation_sort_order_equal: {
options = {
comparisons: true,
}
input: { (a = parseInt('100')) == a }
expect: { (a = parseInt('100')) == a }
input: {
console.log((a = parseInt("100")) == a);
}
expect: {
console.log((a = parseInt("100")) == a);
}
expect_stdout: "true"
}
tranformation_sort_order_unequal: {
transformation_sort_order_unequal: {
options = {
comparisons: true,
}
input: { (a = parseInt('100')) != a }
expect: { (a = parseInt('100')) != a }
input: {
console.log((a = parseInt("100")) != a);
}
expect: {
console.log((a = parseInt("100")) != a);
}
expect_stdout: "false"
}
tranformation_sort_order_lesser_or_equal: {
transformation_sort_order_lesser_or_equal: {
options = {
comparisons: true,
}
input: { (a = parseInt('100')) <= a }
expect: { (a = parseInt('100')) <= a }
input: {
console.log((a = parseInt("100")) <= a);
}
expect: {
console.log((a = parseInt("100")) <= a);
}
expect_stdout: "true"
}
tranformation_sort_order_greater_or_equal: {
transformation_sort_order_greater_or_equal: {
options = {
comparisons: true,
}
input: { (a = parseInt('100')) >= a }
expect: { (a = parseInt('100')) >= a }
}
input: {
console.log((a = parseInt("100")) >= a);
}
expect: {
console.log((a = parseInt("100")) >= a);
}
expect_stdout: "true"
}

View File

@@ -53,11 +53,21 @@ mangle_props: {
);
}
expect_stdout: "1 1 1 2 2 2 3 3 3 4 4 4 5 5"
expect_warnings: [
"INFO: Preserving reserved property undefined",
"INFO: Preserving reserved property NaN",
"INFO: Preserving reserved property Infinity",
"INFO: Preserving reserved property -Infinity",
"INFO: Preserving reserved property null",
"INFO: Preserving reserved property log",
]
}
numeric_literal: {
mangle = {
properties: true,
properties: {
domprops: true,
},
}
beautify = {
beautify: true,
@@ -106,12 +116,18 @@ numeric_literal: {
"4 5 4 4",
"8 7 8",
]
expect_warnings: [
"INFO: Mapping property 0x25 to o",
"INFO: Mapping property 1E42 to b",
"INFO: Preserving reserved property log",
]
}
identifier: {
mangle = {
properties: {
builtins: true,
domprops: true,
},
}
input: {

View File

@@ -15,7 +15,7 @@ collapse: {
var a;
b = c();
a = typeof b === 'function' ? b() : b;
return 'stirng' == typeof a && d();
return 'string' == typeof a && d();
}
function f3(c) {
var a;
@@ -41,7 +41,7 @@ collapse: {
return void 0 !== ('function' === typeof b ? b() : b) && c();
}
function f2(b) {
return 'stirng' == typeof ('function' === typeof (b = c()) ? b() : b) && d();
return 'string' == typeof ('function' === typeof (b = c()) ? b() : b) && d();
}
function f3(c) {
var a;

195
test/compress/issue-5614.js Normal file
View File

@@ -0,0 +1,195 @@
record_update: {
options = {
loops: true,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var value = { a: 42, b: "PASS" };
var unused = _Utils_update(value, { b: "FAIL" });
function _Utils_update(oldRecord, updatedFields) {
var newRecord = {};
for (var key in oldRecord)
newRecord[key] = oldRecord[key];
for (var key in updatedFields)
newRecord[key] = updatedFields[key];
return newRecord;
}
}
expect: {}
}
currying: {
options = {
inline: true,
passes: 2,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function F(arity, fun, wrapper) {
wrapper.a = arity;
wrapper.f = fun;
return wrapper;
}
function F2(fun) {
return F(2, fun, function(a) {
return function(b) {
return fun(a, b);
};
});
}
function _Utils_eq(x, y) {
var pair, stack = [], isEqual = _Utils_eqHelp(x, y, 0, stack);
while (isEqual && (pair = stack.pop()))
isEqual = _Utils_eqHelp(pair.a, pair.b, 0, stack);
return isEqual;
}
var _Utils_equal = F2(_Utils_eq);
}
expect: {}
}
conditional_property_write: {
options = {
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
var o = {};
if (a)
o.p = console.log("foo");
else
o.q = console.log("bar");
o.r = console.log("baz");
}
f(42);
f(null);
}
expect: {
function f(a) {
if (a)
console.log("foo");
else
console.log("bar");
console.log("baz");
}
f(42);
f(null);
}
expect_stdout: [
"foo",
"baz",
"bar",
"baz",
]
}
reassign_1: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS", b = "FAIL";
(b = a).toString();
console.log(b);
}
expect: {
var b = "FAIL";
(b = "PASS").toString();
console.log(b);
}
expect_stdout: "PASS"
}
reassign_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = "PASS";
if (false) {
a = null + 0;
a();
}
console.log(a);
}
expect: {
var a = "PASS";
if (false) {
a = 0;
a();
}
console.log(a);
}
expect_stdout: "PASS"
}
reassign_3: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0;
(a = a || "PASS").toString();
console.log(a);
}
expect: {
var a = 0;
(a = (0, "PASS")).toString();
console.log(a);
}
expect_stdout: "PASS"
}
retain_instance_write: {
options = {
pure_getters: true,
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
return a;
}
function g() {
var o = {};
var b = new f(o);
if (console)
b.p = "PASS";
return o;
}
console.log(g().p);
}
expect: {
function f(a) {
return a;
}
function g() {
var o = {};
var b = new f(o);
if (console)
b.p = "PASS";
return o;
}
console.log(g().p);
}
expect_stdout: "PASS"
}

View File

@@ -1,6 +1,7 @@
dont_reuse_prop: {
mangle = {
properties: {
domprops: true,
regex: /asd/,
},
}
@@ -19,11 +20,17 @@ dont_reuse_prop: {
console.log(obj.a);
}
expect_stdout: "123"
expect_warnings: [
"INFO: Preserving excluded property a",
"INFO: Mapping property asd to b",
"INFO: Preserving reserved property log",
]
}
unmangleable_props_should_always_be_reserved: {
mangle = {
properties: {
domprops: true,
regex: /asd/,
},
}
@@ -42,4 +49,9 @@ unmangleable_props_should_always_be_reserved: {
console.log(obj.a);
}
expect_stdout: "123"
expect_warnings: [
"INFO: Preserving excluded property a",
"INFO: Mapping property asd to b",
"INFO: Preserving reserved property log",
]
}

View File

@@ -1,17 +1,18 @@
keep_var_for_in: {
options = {
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
(function(obj){
(function(obj) {
var foo = 5;
for (var i in obj)
return foo;
})();
}
expect: {
(function(obj){
(function(obj) {
var i, foo = 5;
for (i in obj)
return foo;

View File

@@ -570,7 +570,7 @@ inlined_assignments: {
expect_stdout: "PASS"
}
inilne_for: {
inline_for: {
options = {
inline: true,
join_vars: true,
@@ -590,7 +590,7 @@ inilne_for: {
expect_stdout: "PASS"
}
inilne_var: {
inline_var: {
options = {
inline: true,
join_vars: true,

View File

@@ -3845,3 +3845,47 @@ issue_5471_2: {
}
expect_stdout: "PASS"
}
issue_5714: {
options = {
inline: true,
join_vars: true,
loops: true,
merge_vars: true,
unused: true,
}
input: {
"use strict";
console.log(function() {
var i = 1;
while (i--) {
var a = function f(b) {
console.log(b);
var c = function(d) {
console.log(typeof d);
}(console);
}();
var e = 42;
}
return e;
}());
}
expect: {
"use strict";
console.log(function() {
for (var i = 1; i--;) {
var b = void 0;
console.log(b);
b = console,
console.log(typeof b);
var e = 42;
}
return e;
}());
}
expect_stdout: [
"undefined",
"object",
"42",
]
}

View File

@@ -173,7 +173,9 @@ numeric_literal: {
side_effects: true,
}
mangle = {
properties: true,
properties: {
domprops: true,
},
}
beautify = {
beautify: true,

View File

@@ -133,6 +133,7 @@ evaluate_string_length: {
mangle_properties_1: {
mangle = {
properties: {
domprops: true,
keep_quoted: false,
},
}
@@ -147,17 +148,18 @@ mangle_properties_1: {
a["a"] = "bar";
a.b = "red";
x = {o: 10};
a.r(x.o, a.a);
a['r']({b: "blue", a: "baz"});
a.run(x.o, a.a);
a['run']({b: "blue", a: "baz"});
}
}
mangle_properties_2: {
mangle = {
properties: {
domprops: true,
reserved: [
"value",
]
],
},
}
input: {
@@ -199,6 +201,24 @@ mangle_properties_2: {
]
}
mangle_properties_3: {
mangle = {
properties: true,
}
input: {
console.log({
[(console, "foo")]: "PASS",
}.foo);
}
expect: {
console.log({
[(console, "o")]: "PASS",
}.o);
}
expect_stdout: "PASS"
node_version: ">=4"
}
mangle_unquoted_properties: {
options = {
evaluate: true,
@@ -207,6 +227,7 @@ mangle_unquoted_properties: {
mangle = {
properties: {
builtins: true,
domprops: true,
keep_quoted: true,
},
}
@@ -308,6 +329,7 @@ mangle_debug_suffix_keep_quoted: {
properties: {
builtins: true,
debug: "XYZ",
domprops: true,
keep_quoted: true,
reserved: [],
},
@@ -353,6 +375,68 @@ mangle_debug_suffix_keep_quoted: {
}
}
keep_substituted_property: {
options = {
evaluate: true,
properties: true,
reduce_vars: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
var o = { p: [] };
function f(b) {
return o[b];
}
function g() {
var a = "p";
return o[a] === f(a);
}
console.log(g() ? "PASS" : "FAIL");
}
expect: {
var o = { p: [] };
function f(n) {
return o[n];
}
function g() {
var n = "p";
return o.p === f(n);
}
console.log(g() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
keep_substituted_property_quotes: {
options = {
evaluate: true,
properties: true,
reduce_vars: true,
}
beautify = {
keep_quoted_props: true,
}
input: {
function f(o) {
var a = "p";
return o[a];
}
console.log(f({ p: "PASS" }));
}
expect: {
function f(o) {
var a = "p";
return o["p"];
}
console.log(f({ p: "PASS" }));
}
expect_stdout: "PASS"
}
first_256_chars_as_properties: {
beautify = {
ascii_only: true,
@@ -899,12 +983,15 @@ issue_2256: {
},
}
input: {
({ "keep": 1 });
g.keep = g.change;
({ "keep": 42 });
global.keep = global.change = "PASS";
console.log(keep);
}
expect: {
g.keep = g.g;
global.keep = global.l = "PASS";
console.log(keep);
}
expect_stdout: "PASS"
}
lhs_prop_1: {
@@ -1580,3 +1667,163 @@ issue_5177: {
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5682_in_1: {
mangle = {
properties: true,
}
input: {
function f(a) {
return "foo" in a;
}
var o = {};
var p = "foo";
o[p] = 42;
console.log(f(o) ? "PASS" : "FAIL");
}
expect: {
function f(o) {
return "foo" in o;
}
var o = {};
var p = "foo";
o[p] = 42;
console.log(f(o) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_5682_in_2: {
mangle = {
properties: true,
}
input: {
function f(a) {
return "foo" in a;
}
var o = { foo: 42 };
console.log(f(o) ? "PASS" : "FAIL");
}
expect: {
function f(o) {
return "o" in o;
}
var o = { o: 42 };
console.log(f(o) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_5682_dot_1: {
mangle = {
properties: true,
}
input: {
function f(a) {
return a.foo;
}
var o = {};
var p = "foo";
o[p] = "PASS";
console.log(f(o));
}
expect: {
function f(o) {
return o.foo;
}
var o = {};
var p = "foo";
o[p] = "PASS";
console.log(f(o));
}
expect_stdout: "PASS"
}
issue_5682_dot_2: {
mangle = {
properties: true,
}
input: {
function f(a) {
return a.foo;
}
var o = { foo: "PASS" };
console.log(f(o));
}
expect: {
function f(o) {
return o.o;
}
var o = { o: "PASS" };
console.log(f(o));
}
expect_stdout: "PASS"
}
issue_5682_dot_2_computed: {
mangle = {
properties: true,
}
input: {
function f(a) {
return a.foo;
}
var o = { ["foo"]: "PASS" };
console.log(f(o));
}
expect: {
function f(o) {
return o.o;
}
var o = { ["o"]: "PASS" };
console.log(f(o));
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5682_sub_1: {
mangle = {
properties: true,
}
input: {
function f(a) {
return a["foo"];
}
var o = {};
var p = "foo";
o[p] = "PASS";
console.log(f(o));
}
expect: {
function f(o) {
return o["foo"];
}
var o = {};
var p = "foo";
o[p] = "PASS";
console.log(f(o));
}
expect_stdout: "PASS"
}
issue_5682_sub_2: {
mangle = {
properties: true,
}
input: {
function f(a) {
return a["foo"];
}
var o = { foo: "PASS" };
console.log(f(o));
}
expect: {
function f(o) {
return o["o"];
}
var o = { o: "PASS" };
console.log(f(o));
}
expect_stdout: "PASS"
}

View File

@@ -1540,10 +1540,12 @@ this_toString: {
issue_4803: {
options = {
hoist_vars: true,
join_vars: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var o = {

View File

@@ -2488,7 +2488,7 @@ side_effects_assign: {
console.log(a);
}
expect: {
var a = typeof void (a && a.in);
var a = "undefined";
console.log(a);
}
expect_stdout: "undefined"
@@ -2530,7 +2530,8 @@ pure_getters_2: {
var a = a && a.b;
}
expect: {
var a = a && a.b;
var a;
a && a.b;
}
}
@@ -5424,7 +5425,7 @@ issue_2774: {
get a() {
var b;
(b = true) && b.c;
b = void 0;
void 0;
}
}.a);
}
@@ -7896,3 +7897,168 @@ issue_5434: {
}
expect_stdout: "PASS"
}
issue_5623: {
options = {
collapse_vars: true,
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = 0;
function f() {
var b = a;
a = b;
}
f && f((a++ && a).toString());
console.log(a);
}
expect: {
var a = 0;
function f() {
var b;
a = a;
}
f((a++ && a).toString());
console.log(a);
}
expect_stdout: "1"
}
issue_5716_1: {
options = {
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return b++ + (a = b);
}();
}
f();
console.log(a);
}
expect: {
c = [ c, c ],
void (c = ++c);
var c;
console.log(c);
}
expect_stdout: "NaN"
}
issue_5716_2: {
options = {
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b += 4) + (a = b += 2);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = (c = [ c, c ]) + 4 + 2);
var c;
console.log(c);
}
expect_stdout: ",42"
}
issue_5716_3: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b = b + 4) + (a = b += 2);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = (c = [ c, c ]) + 4 + 2);
var c;
console.log(c);
}
expect_stdout: ",42"
}
issue_5716_4: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b = true | b) + (a = b *= 42);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = ((c = [ c, c ]) | true) * 42);
var c;
console.log(c);
}
expect_stdout: "42"
}
issue_5716_5: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(function() {
return 0 || (a = 42 | a);
var a = function() {
return a;
};
}());
}
expect: {
console.log(function() {
return 0 || (a |= 42);
var a = function() {
return a;
};
}());
}
expect_stdout: "42"
}

View File

@@ -1624,3 +1624,21 @@ issue_5552_4: {
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5705: {
options = {
reduce_vars: true,
rests: true,
unused: true,
}
input: {
(function(...a) {
var b = { ...a };
})(console.log("PASS"));
}
expect: {
(function() {})(console.log("PASS"));
}
expect_stdout: "PASS"
node_version: ">=8.3.0"
}

View File

@@ -13,12 +13,12 @@ collapse_vars_1: {
}
input: {
var a;
[ ...a = "PASS", "PASS"].slice();
[ ...a = "PASS", "PASS" ].slice();
console.log(a);
}
expect: {
var a;
[ ...a = "PASS", "PASS"].slice();
[ ...a = "PASS", "PASS" ].slice();
console.log(a);
}
expect_stdout: "PASS"
@@ -33,7 +33,7 @@ collapse_vars_2: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
[ ...42, "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -42,7 +42,7 @@ collapse_vars_2: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
[ ...42, "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -58,7 +58,7 @@ collapse_vars_3: {
input: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
[ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -66,7 +66,7 @@ collapse_vars_3: {
expect: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
[ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) {
console.log(a);
}

View File

@@ -127,7 +127,7 @@ if_return: {
if (w) {
if (y) return;
} else if (z) return;
return x != y && (x && w(), y && z()), !0;
return x != y && (x && w(), y) && z(), !0;
}
}
}

View File

@@ -194,6 +194,43 @@ scope_adjustment_let: {
node_version: ">=4"
}
escaped_const: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
const log = console.log;
log("PASS");
}
expect: {
var log = console.log;
log("PASS");
}
expect_stdout: "PASS"
}
escaped_let: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
let log = console.log;
log("PASS");
}
expect: {
"use strict";
var log = console.log;
log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4191_const: {
options = {
functions: true,
@@ -645,3 +682,165 @@ issue_5516: {
expect_stdout: "function"
node_version: ">=4"
}
issue_5697_1: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
const a = k;
console.log(a);
}
})();
}
}());
}
expect: {
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
}
issue_5697_2: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
"use strict";
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
let a = k;
console.log(a);
}
})();
}
}());
}
expect: {
"use strict";
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=4"
}
issue_5697_3: {
options = {
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
varify: true,
}
input: {
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
const a = k;
console.log(a);
}
})();
}
}());
}
expect: {
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
}
issue_5697_4: {
options = {
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
varify: true,
}
input: {
"use strict";
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
let a = k;
console.log(a);
}
})();
}
}());
}
expect: {
"use strict";
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=4"
}

View File

@@ -1735,3 +1735,344 @@ issue_5576: {
]
node_version: ">=10"
}
issue_5663: {
options = {
toplevel: true,
unused: true,
}
input: {
var [ , a ] = function*() {
console.log("foo");
yield console.log("bar");
console.log("baz");
yield console.log("moo");
console.log("moz");
yield FAIL;
}();
}
expect: {
var [ , , ] = function*() {
console.log("foo");
yield console.log("bar");
console.log("baz");
yield console.log("moo");
console.log("moz");
yield FAIL;
}();
}
expect_stdout: [
"foo",
"bar",
"baz",
"moo",
]
node_version: ">=6"
}
issue_5679_1: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
b;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_2: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return undefined;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return void 0;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_3: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return undefined;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
return void 0;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_4: {
options = {
conditionals: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return undefined;
else
return undefined;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
return b, void 0;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_5: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_6: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return;
else
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
if (!b)
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5684: {
options = {
conditionals: true,
if_return: true,
}
input: {
(async function*() {
switch (42) {
default:
if (console.log("PASS"))
return;
return null;
case false:
}
})().next();
}
expect: {
(async function*() {
switch (42) {
default:
return console.log("PASS") ? void 0 : null;
case false:
}
})().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5707: {
options = {
hoist_props: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
yields: true,
}
input: {
var a, b;
function* f(c = (b = 42, console.log("PASS"))) {}
b = f();
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5710: {
options = {
conditionals: true,
if_return: true,
}
input: {
(async function*() {
try {
switch (42) {
case 42:
{
if (console.log("PASS"))
return;
return null;
}
break;
}
} finally {}
})().next();
}
expect: {
(async function*() {
try {
switch (42) {
case 42:
if (console.log("PASS"))
return;
return null;
break;
}
} finally {}
})().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}

View File

@@ -62,6 +62,7 @@ if (typeof phantom == "undefined") {
var cmd = process.platform == "win32" ? "npm.cmd" : "npm";
function npm(args, done) {
args.push("--loglevel=error");
child_process.spawn(cmd, args, { stdio: [ "ignore", 1, 2 ] }).on("exit", done);
}
@@ -72,9 +73,12 @@ if (typeof phantom == "undefined") {
"is-my-json-valid@2.20.5",
"phantomjs-prebuilt@2.1.14",
"--no-audit",
"--no-fund",
"--no-optional",
"--no-save",
"--no-strict-ssl",
"--no-update-notifier",
"--production",
], function(code) {
if (code) {
console.log("npm install failed with code", code);

View File

@@ -400,7 +400,7 @@ describe("comments", function() {
assert.strictEqual(ast.print_to_string({comments: "all"}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8");
});
it("Should be able to filter commments with the 'some' option", function() {
it("Should be able to filter comments with the 'some' option", function() {
var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/");
assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/");
});

View File

@@ -348,7 +348,7 @@ describe("Directives", function() {
'"use strict";doSomething("foo");'
],
[
// Nothing gets optimised in the compressor because "use asm" is the first statement
// Nothing gets optimized in the compressor because "use asm" is the first statement
'"use asm";"use\\x20strict";1+1;',
'"use asm";"use\\x20strict";1+1;'
],

View File

@@ -12,17 +12,16 @@ describe("let", function() {
s += '}';
var result = UglifyJS.minify(s, {
compress: false,
}).code;
});
if (result.error) throw result.error;
// Verify that select keywords and reserved keywords not produced
[
"do",
"let",
"var",
].forEach(function(name) {
assert.strictEqual(result.indexOf("var " + name + "="), -1);
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
});
// Verify that the variable names that appeared immediately before
// and after the erroneously generated variable name still exist
// to show the test generated enough symbols.
@@ -31,27 +30,29 @@ describe("let", function() {
"eet", "fet",
"rar", "oar",
].forEach(function(name) {
assert.notStrictEqual(result.indexOf("var " + name + "="), -1);
assert.notStrictEqual(result.code.indexOf("var " + name + "="), -1);
});
});
it("Should quote mangled properties that are reserved keywords", function() {
var s = '"rrrrrnnnnniiiiiaaaaa";';
for (var i = 0; i < 18000; i++) {
s += "v.b" + i + ";";
s += "v.b" + i + "=v;";
}
var result = UglifyJS.minify(s, {
compress: false,
ie: true,
mangle: {
properties: true,
}
}).code;
properties: {
domprops: true,
},
},
});
if (result.error) throw result.error;
[
"in",
"var",
].forEach(function(name) {
assert.notStrictEqual(result.indexOf(name), -1);
assert.notStrictEqual(result.indexOf('v["' + name + '"]'), -1);
assert.notStrictEqual(result.code.indexOf('v["' + name + '"]'), -1);
});
});
it("Should parse `let` as name correctly", function() {

View File

@@ -110,10 +110,12 @@ describe("minify", function() {
var result = UglifyJS.minify(code, {
compress: false,
mangle: {
properties: true,
toplevel: true
properties: {
domprops: true,
},
toplevel: true,
},
nameCache: cache
nameCache: cache,
});
if (result.error) throw result.error;
original += code;
@@ -188,32 +190,30 @@ describe("minify", function() {
it("Shouldn't mangle quoted properties", function() {
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
var result = UglifyJS.minify(js, {
compress: {
properties: false
},
compress: true,
mangle: {
properties: {
keep_quoted: true
}
domprops: true,
keep_quoted: true,
},
},
output: {
keep_quoted_props: true,
quote_style: 3
}
quote_style: 3,
},
});
assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};');
assert.strictEqual(result.code, 'a["foo"]="bar",a.a="red",x={"bar":10};');
});
it("Should not mangle quoted property within dead code", function() {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change;', {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change = 42;', {
mangle: {
properties: {
keep_quoted: true
}
}
keep_quoted: true,
},
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g;");
assert.strictEqual(result.code, "g.keep=g.g=42;");
});
});

View File

@@ -449,6 +449,27 @@ describe("test/reduce.js", function() {
].join("\n"));
});
it("Should transform `export default function` correctly", function() {
if (semver.satisfies(process.version, "<8")) return;
var code = [
"export default function f(a) {",
" for (var k in a)",
" console.log(k);",
" (async function() {})();",
"}",
"f(this);",
].join("\n");
var result = reduce_test(code, {
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "mangle": false',
"// }",
].join("\n"));
});
it("Should transform `export default (function)` correctly", function() {
var code = [
"for (var k in this)",
" console.log(k);",

View File

@@ -245,7 +245,7 @@ describe("sourcemaps", function() {
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
});
it("Should work in presence of unrecognised annotations", function() {
it("Should work in presence of unrecognized annotations", function() {
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false,
mangle: false,

View File

@@ -1,6 +1,6 @@
var fs = require("fs");
new Function("exports", require("../tools/node").FILES.map(function(file) {
new Function("domprops", "exports", require("../tools/node").FILES.map(function(file) {
if (/exports\.js$/.test(file)) file = require.resolve("./exports");
return fs.readFileSync(file, "utf8");
}).join("\n\n"))(exports);
}).join("\n\n"))(require("../tools/domprops.json"), exports);

View File

@@ -466,7 +466,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
}
else if (node instanceof U.AST_VarDef) {
if (node.value && !(parent instanceof U.AST_Const)) {
if (node.value && !(node.name instanceof U.AST_Destructured || parent instanceof U.AST_Const)) {
node.start._permute++;
CHANGED = true;
return new U.AST_VarDef({

View File

@@ -48,6 +48,8 @@ done
nvs use $NODE
node --version
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set optional false
npm config set save false
npm config set strict-ssl false

View File

@@ -25,7 +25,7 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
} while (prev !== stdout);
return stdout;
} : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) {
if ([
var stdout = ([
/\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/,
/\basync([ \t]+|[ \t]*#)[^\s()[\]{}#:;,.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
/\basync[ \t]*\*[ \t]*[^\s()[\]{}#:;,.&|!~=*%/+-]+\s*\(/,
@@ -33,11 +33,8 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
].some(function(pattern) {
return pattern.test(code);
})) {
return run_code_exec(code, toplevel, timeout);
} else {
return run_code_vm(code, toplevel, timeout);
}
}) ? run_code_exec : run_code_vm)(code, toplevel, timeout);
return stdout.length > 1000 ? stdout.slice(0, 1000) + "…《" + stdout.length + "》" : stdout;
};
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
@@ -57,7 +54,7 @@ exports.patch_module_statements = function(code) {
strict_mode = match;
return "";
}).replace(/\bexport(?:\s*\{[^{}]*}\s*?(?:$|\n|;)|\s+default\b(?:\s*(\(|\{|class\s*\{|class\s+(?=extends\b)|(?:async\s+)?function\s*(?:\*\s*)?\())?|\b)/g, function(match, header) {
if (/^export\s+default/.test(match)) has_default = "var _uglify_export_default_;";
if (/^export\s+default/.test(match)) has_default = "function _uglify_export_default_() {}";
if (!header) return "";
if (header.length == 1) return "0, " + header;
var name = "_uglify_export_default_";
@@ -286,6 +283,7 @@ function run_code_exec(code, toplevel, timeout) {
var result = spawnSync(process.argv[0], [ '--max-old-space-size=2048' ], {
encoding: "utf8",
input: code,
maxBuffer: 1073741824,
stdio: "pipe",
timeout: timeout || 5000,
});

View File

@@ -2,15 +2,18 @@ var get = require("https").get;
var parse = require("url").parse;
var base, token, run_number;
var expires = Date.now() + (6 * 60 - 10) * 60 * 1000;
exports.init = function(url, auth, num) {
base = url;
token = auth;
run_number = num;
};
exports.should_stop = function(callback) {
if (Date.now() > expires) return callback();
read(base + "/actions/runs?per_page=100", function(reply) {
if (!reply || !Array.isArray(reply.workflow_runs)) return;
var runs = reply.workflow_runs.sort(function(a, b) {
var runs = verify(reply, "workflow_runs").filter(function(workflow) {
return workflow.status != "completed";
}).sort(function(a, b) {
return b.run_number - a.run_number;
});
var found = false, remaining = 20;
@@ -19,15 +22,13 @@ exports.should_stop = function(callback) {
do {
workflow = runs.pop();
if (!workflow) return;
if (is_cron(workflow) && workflow.run_number == run_number) found = true;
} while (!found && workflow.status == "completed");
if (!is_cron(workflow)) break;
if (workflow.run_number == run_number) found = true;
} while (!found);
read(workflow.jobs_url, function(reply) {
if (!reply || !Array.isArray(reply.jobs)) return;
if (!reply.jobs.every(function(job) {
if (job.status == "completed") return true;
remaining--;
return found || !is_cron(workflow);
})) return;
verify(reply, "jobs").forEach(function(job) {
if (job.status != "completed") remaining--;
});
if (remaining >= 0) {
next();
} else {
@@ -70,3 +71,12 @@ function read(url, callback) {
done();
});
}
function verify(reply, field) {
if (!reply) return [];
var values = reply[field];
if (!Array.isArray(values)) return [];
return values.filter(function(value) {
return value;
});
}

View File

@@ -1142,7 +1142,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
}
case STMT_FUNC_EXPR:
// "In non-strict mode code, functions can only be declared at top level, inside a block, or ..."
// (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block)
// (don't make func decls in `if`; it's only a parser thing because you can't call them without a block)
return "{" + createFunction(recurmax, NO_DEFUN, canThrow, stmtDepth) + "}";
case STMT_TRY:
// catch var could cause some problems

View File

@@ -15,13 +15,13 @@ exports.FILES = [
require.resolve("./exports.js"),
];
new Function("exports", function() {
new Function("domprops", "exports", function() {
var code = exports.FILES.map(function(file) {
return fs.readFileSync(file, "utf8");
});
code.push("exports.describe_ast = " + describe_ast.toString());
return code.join("\n\n");
}())(exports);
}())(require("./domprops.json"), exports);
function to_comment(value) {
if (typeof value != "string") value = JSON.stringify(value, function(key, value) {