Compare commits

..

127 Commits

Author SHA1 Message Date
Alex Lam S.L
b23b333d9d v3.13.10 2021-06-27 22:59:34 +08:00
Alex Lam S.L
7621527a5f fix corner case in functions (#5037)
fixes #5036
2021-06-25 03:43:52 +08:00
Alex Lam S.L
1a064b6e74 fix corner case in functions (#5035)
fixes #5034
2021-06-24 19:43:46 +08:00
Alex Lam S.L
82772ccb12 workaround Safari quirks (#5033)
closes #5032
2021-06-24 17:09:19 +08:00
Alex Lam S.L
7cbcd11440 fix corner case in dead_code (#5031)
fixes #5030
2021-06-23 22:56:28 +08:00
Alex Lam S.L
980dbde171 fix corner cases in booleans (#5029)
fixes #5028
2021-06-23 07:42:57 +08:00
Alex Lam S.L
8b05677c15 fix corner case in collapse_vars (#5026)
fixes #5025
2021-06-23 05:03:11 +08:00
Alex Lam S.L
95090dbf24 fix corner case in side_effects (#5024)
fixes #5023
2021-06-23 00:36:07 +08:00
Alex Lam S.L
7c5b6f349e enhance booleans (#5022)
closes #5021
2021-06-23 00:35:50 +08:00
Alex Lam S.L
e9c902b044 fix corner cases in dead_code & inline (#5020)
fixes #5019
2021-06-21 22:28:54 +08:00
Alex Lam S.L
111366fca0 fix corner case in collapse_vars (#5018)
fixes #5017
2021-06-21 11:12:45 +08:00
Alex Lam S.L
e368d39715 fix corner cases in reduce_vars & side_effects (#5016)
fixes #5015
2021-06-21 03:13:05 +08:00
Alex Lam S.L
fd8dec61ad enhance dead_code (#5014) 2021-06-20 15:30:04 +08:00
Alex Lam S.L
7880568d15 fix corner case in switches (#5013)
fixes #5012
2021-06-15 23:51:53 +08:00
Alex Lam S.L
21fc8f4630 fix corner case in switches (#5011)
fixes #5010
2021-06-15 20:59:53 +08:00
Alex Lam S.L
bf76e35772 fix corner case in switches (#5009)
fixes #5008
2021-06-15 18:27:55 +08:00
Alex Lam S.L
ac1262dc97 fix corner case in arguments (#5007)
fixes #5006
2021-06-15 12:53:22 +08:00
Alex Lam S.L
498ac83541 enhance switches (#5005)
closes #5004
2021-06-15 10:32:39 +08:00
Alex Lam S.L
6fc7a2ab6a fix corner case in side_effects (#5002)
fixes #5001
2021-06-13 20:29:14 +08:00
Alex Lam S.L
f8b2215145 fix corner cases in parse & unused (#5000) 2021-06-13 00:10:01 +08:00
Alex Lam S.L
70ceda5398 minor clean-up (#4998) 2021-06-12 09:20:06 +08:00
Alex Lam S.L
ce75477670 fix corner case in reduce_vars (#4997)
fixes #4996
2021-06-10 08:03:17 +08:00
Alex Lam S.L
e70b84895c fix corner cases in loops & unused (#4995)
fixes #4994
2021-06-10 07:58:33 +08:00
Alex Lam S.L
8dbf0b042e v3.13.9 2021-06-05 05:21:10 +08:00
Alex Lam S.L
83f7887e5d fix corner case in unused (#4993)
fixes #4992
2021-06-03 20:23:14 +08:00
Alex Lam S.L
dff7b48921 workaround GitHub Actions issues (#4991) 2021-06-02 02:43:34 +08:00
Alex Lam S.L
f4f0d2a2dd workaround transient npm failures (#4989) 2021-05-30 17:19:29 +08:00
Alex Lam S.L
06e3dbc089 improve handling of declaration statements (#4980) 2021-05-30 16:32:48 +08:00
Alex Lam S.L
55a230daa8 fix corner case in awaits (#4988)
fixes #4987
2021-05-30 13:40:13 +08:00
Alex Lam S.L
23b9f36bd8 fix corner case in hoist_props (#4986)
fixes #4985
2021-05-30 12:00:32 +08:00
Alex Lam S.L
7e88d52fae fix corner case in dead_code (#4984) 2021-05-30 11:07:55 +08:00
Alex Lam S.L
b9d5bba5fb fix corner case in dead_code (#4983)
fixes #4982
2021-05-30 09:00:48 +08:00
Alex Lam S.L
8d23496e0f fix corner case in dead_code (#4981) 2021-05-30 03:16:18 +08:00
Alex Lam S.L
260431f4e0 improve handling of lexical scope (#4979) 2021-05-29 12:48:34 +08:00
Alex Lam S.L
7fa1dea9d0 fix corner cases in collapse_vars (#4978)
fixes #4977
2021-05-29 08:57:24 +08:00
Alex Lam S.L
d40631fd44 fix corner cases in awaits (#4976)
fixes #4974
fixes #4975
2021-05-29 01:47:54 +08:00
Alex Lam S.L
d320a6cde2 fix corner case in awaits (#4973)
fixes #4972
2021-05-28 10:53:10 +08:00
Alex Lam S.L
8cd95dd263 enhance awaits (#4971) 2021-05-28 08:47:37 +08:00
Alex Lam S.L
749a828fc5 fix corner case in collapse_vars (#4970) 2021-05-28 06:32:43 +08:00
Alex Lam S.L
ab42a90edb enhance awaits (#4969) 2021-05-28 00:57:14 +08:00
Alex Lam S.L
362abe0ffb enhance unused (#4968) 2021-05-26 22:25:07 +08:00
Alex Lam S.L
e3798d9a76 fix corner case in arguments (#4967) 2021-05-26 22:24:26 +08:00
Alex Lam S.L
c8d10b7cde v3.13.8 2021-05-26 19:17:50 +08:00
Alex Lam S.L
7caab39e26 fix corner case in mangle (#4966)
fixes #4965
2021-05-26 06:21:52 +08:00
Alex Lam S.L
eff45eac0e fix corner case in ie8 (#4963)
fixes #4962
2021-05-26 00:12:31 +08:00
Alex Lam S.L
1e787c556b fix corner case in mangle (#4961)
fixes #4960
2021-05-24 11:46:58 +08:00
Alex Lam S.L
df47632ecc fix corner case in ie8 (#4959)
fixes #4958
2021-05-24 11:24:02 +08:00
Alex Lam S.L
eb08fed120 fix corner case in merge_vars (#4957)
fixes #4956
2021-05-24 09:56:02 +08:00
Alex Lam S.L
8b0c836515 fix corner cases in rename & varify (#4955)
fixes #4954
2021-05-24 06:54:48 +08:00
Alex Lam S.L
5d4e6e3bdc enhance sourceMap (#4953) 2021-05-23 23:57:44 +08:00
Alex Lam S.L
d2a45ba441 fix corner case in parsing private field/method (#4952)
fixes #4951
2021-05-22 10:12:37 +08:00
Alex Lam S.L
de376c3d33 fix corner case in reduce_vars (#4950)
fixes #4949
2021-05-21 18:49:07 +08:00
Alex Lam S.L
4a19575e74 fix corner case in conditionals (#4948)
fixes #4947
2021-05-20 18:08:22 +08:00
Alex Lam S.L
e0695ef549 enhance pure_funcs (#4945) 2021-05-20 07:09:47 +08:00
Alex Lam S.L
d6152e6a76 fix corner case in collapse_vars (#4946) 2021-05-20 05:11:39 +08:00
Alex Lam S.L
d930c705f6 v3.13.7 2021-05-19 02:38:19 +08:00
Alex Lam S.L
254937754c fix corner case in reduce_vars (#4944)
fixes #4943
2021-05-18 05:52:24 +08:00
Alex Lam S.L
ae4dbcb5b9 document v8 quirks (#4942)
closes #4941
2021-05-16 02:13:30 +08:00
Alex Lam S.L
e13615549e fix corner case in pure_getters (#4940)
fixes #4939
2021-05-16 02:12:58 +08:00
Alex Lam S.L
a7698f8845 fix corner case in reduce_vars (#4938)
fixes #4937
2021-05-15 22:38:09 +08:00
Alex Lam S.L
bbed9b13b1 fix corner case in collapse_vars (#4936)
fixes #4935
2021-05-15 22:34:14 +08:00
Alex Lam S.L
2cff7c94e8 fix corner case in reduce_vars (#4934)
fixes #4933
2021-05-15 01:49:46 +08:00
Alex Lam S.L
7576048118 fix corner case in unsafe evaluate (#4932)
fixes #4931
2021-05-14 22:51:19 +08:00
Alex Lam S.L
3c1898fd65 suppress invalid test case generation (#4930) 2021-05-13 19:57:36 +08:00
Alex Lam S.L
e04429350f fix corner case in ie8 (#4929)
fixes #4928
2021-05-13 09:26:57 +08:00
Alex Lam S.L
60f3b55156 fix corner case with optional chain operator (#4927) 2021-05-12 10:12:19 +08:00
Alex Lam S.L
689f8f504d enhance mangle (#4926) 2021-05-11 23:41:32 +08:00
Alex Lam S.L
ae51f76ba7 fix corner case in unused (#4925)
fixes #4924
2021-05-11 20:50:58 +08:00
Alex Lam S.L
7eef86ed05 workaround GitHub Actions issue (#4923) 2021-05-11 18:21:21 +08:00
Alex Lam S.L
b1cfa71131 enhance unused (#4922) 2021-05-11 10:30:20 +08:00
Alex Lam S.L
7b8570f16c v3.13.6 2021-05-11 03:15:16 +08:00
Alex Lam S.L
bb225367cb fix corner case collapse_vars (#4921)
fixes #4920
2021-05-09 02:59:45 +08:00
Alex Lam S.L
bbca9de9cd fix corner case in collapse_vars (#4919)
fixes #4918
2021-05-08 03:58:29 +08:00
Alex Lam S.L
ee9ceb79ca fix corner case in collapse_vars (#4917)
fixes #4916
2021-05-08 02:34:27 +08:00
Alex Lam S.L
ac1f7d689b fix corner case in collapse_vars (#4915)
fixes #4914
2021-05-08 01:14:59 +08:00
Alex Lam S.L
19d232badb fix corner case in unused (#4913)
fixes #4912
2021-05-07 19:38:22 +08:00
Alex Lam S.L
d464be3f3f fix corner case in collapse_vars (#4911)
fixes #4910
2021-05-05 00:03:43 +08:00
Alex Lam S.L
3094eaaa89 fix corner case in collapse_vars (#4909)
fixes #4908
2021-05-04 16:33:52 +08:00
Alex Lam S.L
ce3c35fa8b fix corner case in unused (#4907)
fixes #4906
2021-05-04 06:19:25 +08:00
Alex Lam S.L
5d9224deb8 fix corner cases with template literals (#4903)
fixes #4902
2021-05-03 22:26:20 +08:00
Alex Lam S.L
45b6d23d36 suppress false positives in ufuzz (#4901) 2021-05-03 19:11:53 +08:00
Alex Lam S.L
f0de9a8b5d support optional chaining operator (#4899) 2021-05-03 10:08:29 +08:00
Alex Lam S.L
203f4b7ad9 fix corner case in hoist_vars (#4900)
fixes #4898
2021-05-03 04:05:52 +08:00
Alex Lam S.L
4114431eec fix corner case in collapse_vars (#4896)
fixes #4895
2021-05-02 18:23:18 +08:00
Alex Lam S.L
fb03561799 fix corner case in hoist_vars (#4894)
fixes #4893
2021-05-02 07:28:31 +08:00
Alex Lam S.L
6ab26eef6c fix corner case in collapse_vars (#4892)
fixes #4891
2021-05-02 03:57:17 +08:00
Alex Lam S.L
53b57ee57e enhance reduce_vars & unused (#4890) 2021-05-02 00:19:56 +08:00
Alex Lam S.L
16411dcb87 enhance collapse_vars (#4885) 2021-05-01 21:37:52 +08:00
Alex Lam S.L
8bbfaacdae fix corner case in properties (#4889)
fixes #4888
2021-05-01 07:52:53 +08:00
Alex Lam S.L
df980db4a8 fix corner case in unsafe evaluate (#4887)
fixes #4886
2021-05-01 07:24:39 +08:00
Alex Lam S.L
8e4a19ffec fix corner case in spreads (#4883)
fixes #4882
2021-04-30 22:21:15 +08:00
Alex Lam S.L
d833e66d23 enhance join_vars (#4881) 2021-04-30 11:40:47 +08:00
Alex Lam S.L
8aa650bcf9 v3.13.5 2021-04-30 00:44:50 +08:00
Alex Lam S.L
d576495e5a support #__PURE__ in ESTree (#4879) 2021-04-29 04:13:42 +08:00
Alex Lam S.L
a06e20304b fix corner case in pure_getters (#4877)
fixes #4876
2021-04-27 22:52:37 +08:00
Alex Lam S.L
4cccc01f3e fix corner case in collapse_vars (#4875)
fixes #4874
2021-04-27 08:54:02 +08:00
Alex Lam S.L
97bd56b7e8 improve AST tests & tools (#4873) 2021-04-27 08:53:45 +08:00
Alex Lam S.L
acf951a5bc fix corner case with for [await]...of (#4872) 2021-04-26 05:10:22 +08:00
Alex Lam S.L
324587f769 upgrade AST<->ESTree translation (#4870)
fixes #968
2021-04-26 04:23:52 +08:00
Alex Lam S.L
80efaa2f33 fix corner case with export (#4871) 2021-04-25 22:37:26 +08:00
Alex Lam S.L
a1a212f639 fix corner case in collapse_vars (#4869)
fixes #4868
2021-04-25 05:16:51 +08:00
Alex Lam S.L
a2b1b96752 fix corner case with yield (#4867) 2021-04-25 03:10:12 +08:00
Alex Lam S.L
c296a63fb3 fix corner case in collapse_vars (#4866)
fixes #4865
2021-04-24 20:04:31 +08:00
Alex Lam S.L
10dd9d4eaf enhance collapse_vars (#4864) 2021-04-24 12:45:18 +08:00
Alex Lam S.L
9b8deff64d enhance pure_getters, reduce_vars & unused (#4863) 2021-04-24 07:17:30 +08:00
Alex Lam S.L
f46209b7e5 enhance unsafe side_effects (#4862)
closes #4861
2021-04-23 06:58:14 +08:00
Alex Lam S.L
bddb5a0102 enhance unused (#4858) 2021-04-22 10:58:50 +08:00
Alex Lam S.L
3c161a6662 fix corner case in hoist_vars (#4860)
fixes #4859
2021-04-22 05:47:21 +08:00
Alex Lam S.L
c58e174647 document various ECMAScript bugs (#4857) 2021-04-21 08:33:54 +08:00
Alex Lam S.L
c53af3dfb1 fix corner case in collapse_vars (#4855)
fixes #4854
2021-04-14 01:22:08 +08:00
Alex Lam S.L
f1f4a4dd82 v3.13.4 2021-04-12 04:33:40 +08:00
Alex Lam S.L
ca49f6f41a fix corner case in collapse_vars (#4853)
fixes #4852
2021-04-08 17:50:40 +08:00
Alex Lam S.L
8a82822654 fix corner case in if_return (#4851)
fixes #4848
2021-04-08 08:57:59 +08:00
Alex Lam S.L
ebe4e1ad28 fix corner case in unused (#4850)
fixes #4849
2021-04-08 06:31:15 +08:00
Alex Lam S.L
a37ca558dd reject invalid for await syntax (#4847) 2021-04-07 22:37:15 +08:00
Alex Lam S.L
73a564343b preserve compatibility of quote_style (#4845) 2021-04-07 06:49:12 +08:00
Alex Lam S.L
4870747306 speed up OutputStream (#4844) 2021-04-07 02:57:23 +08:00
Alex Lam S.L
b179a2459f parse octal literals correctly (#4843) 2021-04-07 02:23:35 +08:00
Alex Lam S.L
231c3d7c84 clean up OutputStream (#4842) 2021-04-06 21:34:27 +08:00
Alex Lam S.L
aed758ed5c enhance comparisons & reduce_vars (#4841) 2021-04-03 22:06:05 +08:00
Alex Lam S.L
0df028187d fix corner case in hoist_vars (#4840)
fixes #4839
2021-04-03 10:07:18 +08:00
Alex Lam S.L
10fbf8e295 support mangle.properties on class (#4838) 2021-04-03 06:00:19 +08:00
Alex Lam S.L
cf38b52afa parse import.meta correctly (#4836) 2021-04-03 04:31:29 +08:00
Alex Lam S.L
e755d01a0b fix corner case in unused (#4835)
fixes #4834
2021-04-02 03:55:53 +08:00
Alex Lam S.L
4084948d3b suppress invalid AST transform in --reduce-test (#4833) 2021-04-01 18:52:29 +08:00
Alex Lam S.L
cea1fb5c58 fix corner case in properties (#4832)
fixes #4831
2021-04-01 14:39:51 +08:00
Alex Lam S.L
1947a21824 fix corner case in properties (#4830)
fixes #4829
2021-04-01 07:05:50 +08:00
77 changed files with 8211 additions and 1265 deletions

View File

@@ -8,7 +8,12 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
options: [ '-mb braces', '--ie8 -c', '-mc', '--toplevel -mc passes=3,pure_getters,unsafe' ] options:
- '-mb braces'
- '--ie8 -c'
- '-mc'
- '-p acorn --toplevel -mco spidermonkey'
- '--toplevel -mc passes=3,pure_getters,unsafe'
script: script:
- acorn.sh - acorn.sh
- bootstrap.sh - bootstrap.sh

View File

@@ -2,11 +2,14 @@ name: Fuzzing
on: on:
pull_request: pull_request:
schedule: schedule:
- cron: '*/5 * * * *' - cron: '*/15 * * * *'
workflow_dispatch:
workflow_run:
branches: [ master ]
types: [ completed ]
workflows: [ 'Build testing', CI ]
env: env:
BASE_URL: https://api.github.com/repos/${{ github.repository }} BASE_URL: https://api.github.com/repos/${{ github.repository }}
CAUSE: ${{ github.event_name }}
RUN_NUM: ${{ github.run_number }}
TOKEN: ${{ github.token }} TOKEN: ${{ github.token }}
jobs: jobs:
ufuzz: ufuzz:
@@ -34,8 +37,8 @@ jobs:
shell: bash shell: bash
run: | run: |
. ./test/release/install.sh . ./test/release/install.sh
if [[ $CAUSE == "schedule" ]]; then if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then
node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM
else
node test/ufuzz/job 5000 node test/ufuzz/job 5000
else
node test/ufuzz/job $BASE_URL $TOKEN $GITHUB_RUN_NUMBER
fi fi

View File

@@ -1309,3 +1309,48 @@ To allow for better optimizations, the compiler makes various assumptions:
// Actual: { '42': undefined } // Actual: { '42': undefined }
``` ```
UglifyJS may modify the input which in turn may suppress those errors. UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of JavaScript will throw `SyntaxError` with the following:
```javascript
var await;
async function f() {
class A {
static p = await;
}
}
// SyntaxError: Unexpected reserved word
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of JavaScript will throw `SyntaxError` with the following:
```javascript
var async;
for (async of []);
// SyntaxError: The left-hand side of a for-of loop may not be 'async'.
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of Chrome and Node.js will give incorrect results with the
following:
```javascript
console.log({
...console,
get 42() {
return "FAIL";
},
[42]: "PASS",
}[42]);
// Expected: "PASS"
// Actual: "FAIL"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Earlier versions of JavaScript will throw `TypeError` with the following:
```javascript
(function() {
{
const a = "foo";
}
{
const a = "bar";
}
})();
// TypeError: const 'a' has already been declared
```
UglifyJS may modify the input which in turn may suppress those errors.

View File

@@ -235,10 +235,11 @@ if (options.mangle && options.mangle.properties) {
}); });
} }
} }
if (output == "ast") options.output = { if (/^ast|spidermonkey$/.test(output)) {
ast: true, if (typeof options.output != "object") options.output = {};
code: false, options.output.ast = true;
}; options.output.code = false;
}
if (options.parse && (options.parse.acorn || options.parse.spidermonkey) if (options.parse && (options.parse.acorn || options.parse.spidermonkey)
&& options.sourceMap && options.sourceMap.content == "inline") { && options.sourceMap && options.sourceMap.content == "inline") {
fatal("inline source map only works with built-in parser"); fatal("inline source map only works with built-in parser");
@@ -265,7 +266,9 @@ if (specified["self"]) {
paths = UglifyJS.FILES; paths = UglifyJS.FILES;
} }
if (specified["in-situ"]) { if (specified["in-situ"]) {
if (output || specified["reduce-test"] || specified["self"]) fatal("incompatible options specified"); if (output && output != "spidermonkey" || specified["reduce-test"] || specified["self"]) {
fatal("incompatible options specified");
}
paths.forEach(function(name) { paths.forEach(function(name) {
print(name); print(name);
if (/^ast|spidermonkey$/.test(name)) fatal("invalid file name specified"); if (/^ast|spidermonkey$/.test(name)) fatal("invalid file name specified");
@@ -311,13 +314,43 @@ function run() {
try { try {
if (options.parse) { if (options.parse) {
if (options.parse.acorn) { if (options.parse.acorn) {
var annotations = Object.create(null);
files = convert_ast(function(toplevel, name) { files = convert_ast(function(toplevel, name) {
return require("acorn").parse(files[name], { var content = files[name];
var list = annotations[name] = [];
var prev = -1;
return require("acorn").parse(content, {
allowHashBang: true,
ecmaVersion: "latest",
locations: true, locations: true,
onComment: function(block, text, start, end) {
var match = /[@#]__PURE__/.exec(text);
if (!match) {
if (start != prev) return;
match = [ list[prev] ];
}
while (/\s/.test(content[end])) end++;
list[end] = match[0];
prev = end;
},
preserveParens: true,
program: toplevel, program: toplevel,
sourceFile: name sourceFile: name,
sourceType: "module",
}); });
}); });
files.walk(new UglifyJS.TreeWalker(function(node) {
if (!(node instanceof UglifyJS.AST_Call)) return;
var list = annotations[node.start.file];
var pure = list[node.start.pos];
if (!pure) {
var tokens = node.start.parens;
if (tokens) for (var i = 0; !pure && i < tokens.length; i++) {
pure = list[tokens[i].pos];
}
}
if (pure) node.pure = pure;
}));
} else if (options.parse.spidermonkey) { } else if (options.parse.spidermonkey) {
files = convert_ast(function(toplevel, name) { files = convert_ast(function(toplevel, name) {
var obj = JSON.parse(files[name]); var obj = JSON.parse(files[name]);
@@ -409,16 +442,19 @@ function run() {
return value; return value;
}, 2)); }, 2));
} else if (output == "spidermonkey") { } else if (output == "spidermonkey") {
print(JSON.stringify(UglifyJS.minify(result.code, { print(JSON.stringify(result.ast.to_mozilla_ast(), null, 2));
compress: false,
mangle: false,
output: {
ast: true,
code: false
},
}).ast.to_mozilla_ast(), null, 2));
} else if (output) { } else if (output) {
fs.writeFileSync(output, result.code); var code;
if (result.ast) {
var opts = {};
for (var name in options.output) {
if (!/^ast|code$/.test(name)) opts[name] = options.output[name];
}
code = UglifyJS.AST_Node.from_mozilla_ast(result.ast.to_mozilla_ast()).print_to_string(opts);
} else {
code = result.code;
}
fs.writeFileSync(output, code);
if (result.map) fs.writeFileSync(output + ".map", result.map); if (result.map) fs.writeFileSync(output + ".map", result.map);
} else { } else {
print(result.code); print(result.code);

View File

@@ -56,35 +56,31 @@ function DEFNODE(type, props, methods, base) {
code.push("this.", prop, "=props.", prop, ";"); code.push("this.", prop, "=props.", prop, ";");
}); });
code.push("}"); code.push("}");
var proto = base && new base; var proto = Object.create(base && base.prototype);
if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();"); if (methods.initialize || proto.initialize) code.push("this.initialize();");
code.push("}"); code.push("};");
var ctor = new Function(code.join(""))(); var ctor = new Function(code.join(""))();
if (proto) { ctor.prototype = proto;
ctor.prototype = proto;
ctor.BASE = base;
}
if (base) base.SUBCLASSES.push(ctor);
ctor.prototype.CTOR = ctor; ctor.prototype.CTOR = ctor;
ctor.PROPS = props || null; ctor.prototype.TYPE = ctor.TYPE = type;
ctor.SELF_PROPS = self_props; if (base) {
ctor.SUBCLASSES = []; ctor.BASE = base;
if (type) { base.SUBCLASSES.push(ctor);
ctor.prototype.TYPE = ctor.TYPE = type;
}
if (methods) for (var name in methods) if (HOP(methods, name)) {
if (/^\$/.test(name)) {
ctor[name.substr(1)] = methods[name];
} else {
ctor.prototype[name] = methods[name];
}
} }
ctor.DEFMETHOD = function(name, method) { ctor.DEFMETHOD = function(name, method) {
this.prototype[name] = method; this.prototype[name] = method;
}; };
if (typeof exports !== "undefined") { ctor.PROPS = props;
exports["AST_" + type] = ctor; ctor.SELF_PROPS = self_props;
ctor.SUBCLASSES = [];
for (var name in methods) if (HOP(methods, name)) {
if (/^\$/.test(name)) {
ctor[name.substr(1)] = methods[name];
} else {
ctor.DEFMETHOD(name, methods[name]);
}
} }
if (typeof exports !== "undefined") exports["AST_" + type] = ctor;
return ctor; return ctor;
} }
@@ -261,9 +257,9 @@ var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_s
$documentation: "Base class for all statements introducing a lexical scope", $documentation: "Base class for all statements introducing a lexical scope",
$propdoc: { $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 subscopes",
functions: "[Object/S] like `variables`, but only lists function declarations", functions: "[Dictionary/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope", parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Object/S] a map of name ---> SymbolDef for all variables/functions defined in this scope", variables: "[Dictionary/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
}, },
clone: function(deep) { clone: function(deep) {
var node = this._clone(deep); var node = this._clone(deep);
@@ -506,7 +502,7 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
var AST_Toplevel = DEFNODE("Toplevel", "globals", { var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$documentation: "The toplevel scope", $documentation: "The toplevel scope",
$propdoc: { $propdoc: {
globals: "[Object/S] a map of name ---> SymbolDef for all undeclared names", globals: "[Dictionary/S] a map of name ---> SymbolDef for all undeclared names",
}, },
wrap: function(name) { wrap: function(name) {
var body = this.body; var body = this.body;
@@ -1293,11 +1289,13 @@ function must_be_expressions(node, prop, allow_spread, allow_hole) {
}); });
} }
var AST_Call = DEFNODE("Call", "expression args pure", { var AST_Call = DEFNODE("Call", "args expression optional pure", {
$documentation: "A function call expression", $documentation: "A function call expression",
$propdoc: { $propdoc: {
args: "[AST_Node*] array of arguments",
expression: "[AST_Node] expression to invoke as function", expression: "[AST_Node] expression to invoke as function",
args: "[AST_Node*] array of arguments" optional: "[boolean] whether the expression is optional chaining",
pure: "[string/S] marker for side-effect-free call expression",
}, },
walk: function(visitor) { walk: function(visitor) {
var node = this; var node = this;
@@ -1315,7 +1313,10 @@ var AST_Call = DEFNODE("Call", "expression args pure", {
}); });
var AST_New = DEFNODE("New", null, { var AST_New = DEFNODE("New", null, {
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties",
_validate: function() {
if (this.optional) throw new Error("optional must be false");
},
}, AST_Call); }, AST_Call);
var AST_Sequence = DEFNODE("Sequence", "expressions", { var AST_Sequence = DEFNODE("Sequence", "expressions", {
@@ -1337,11 +1338,12 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
}, },
}); });
var AST_PropAccess = DEFNODE("PropAccess", "expression property", { var AST_PropAccess = DEFNODE("PropAccess", "expression optional property", {
$documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
$propdoc: { $propdoc: {
expression: "[AST_Node] the “container” expression", expression: "[AST_Node] the “container” expression",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" optional: "[boolean] whether the expression is optional chaining",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
}, },
getProperty: function() { getProperty: function() {
var p = this.property; var p = this.property;
@@ -1686,7 +1688,7 @@ var AST_ObjectMethod = DEFNODE("ObjectMethod", null, {
_validate: function() { _validate: function() {
if (!(this.value instanceof AST_LambdaExpression)) throw new Error("value must be AST_LambdaExpression"); if (!(this.value instanceof AST_LambdaExpression)) throw new Error("value must be AST_LambdaExpression");
if (is_arrow(this.value)) throw new Error("value cannot be AST_Arrow or AST_AsyncArrow"); if (is_arrow(this.value)) throw new Error("value cannot be AST_Arrow or AST_AsyncArrow");
if (this.value.name != null) throw new Error("name of class method's lambda must be null"); if (this.value.name != null) throw new Error("name of object method's lambda must be null");
}, },
}, AST_ObjectKeyVal); }, AST_ObjectKeyVal);

File diff suppressed because it is too large Load Diff

View File

@@ -100,7 +100,7 @@ function minify(files, options) {
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]); if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]);
if (options.webkit) set_shorthand("webkit", options, [ "mangle", "output" ]); if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output" ]);
var quoted_props; var quoted_props;
if (options.mangle) { if (options.mangle) {
options.mangle = defaults(options.mangle, { options.mangle = defaults(options.mangle, {
@@ -204,27 +204,29 @@ function minify(files, options) {
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties); if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
if (timings) timings.output = Date.now(); if (timings) timings.output = Date.now();
var result = {}; var result = {};
if (options.output.ast) { var output = defaults(options.output, {
result.ast = toplevel; ast: false,
} code: true,
if (!HOP(options.output, "code") || options.output.code) { });
if (output.ast) result.ast = toplevel;
if (output.code) {
if (options.sourceMap) { if (options.sourceMap) {
options.output.source_map = SourceMap(options.sourceMap); output.source_map = SourceMap(options.sourceMap);
if (options.sourceMap.includeSources) { if (options.sourceMap.includeSources) {
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable"); throw new Error("original source content unavailable");
} else for (var name in files) if (HOP(files, name)) { } else for (var name in files) if (HOP(files, name)) {
options.output.source_map.setSourceContent(name, files[name]); output.source_map.setSourceContent(name, files[name]);
} }
} }
} }
delete options.output.ast; delete output.ast;
delete options.output.code; delete output.code;
var stream = OutputStream(options.output); var stream = OutputStream(output);
toplevel.print(stream); toplevel.print(stream);
result.code = stream.get(); result.code = stream.get();
if (options.sourceMap) { if (options.sourceMap) {
result.map = options.output.source_map.toString(); result.map = output.source_map.toString();
var url = options.sourceMap.url; var url = options.sourceMap.url;
if (url) { if (url) {
result.code = result.code.replace(/\n\/\/# sourceMappingURL=\S+\s*$/, ""); result.code = result.code.replace(/\n\/\/# sourceMappingURL=\S+\s*$/, "");

File diff suppressed because it is too large Load Diff

View File

@@ -49,8 +49,6 @@ function is_some_comments(comment) {
} }
function OutputStream(options) { function OutputStream(options) {
var readonly = !options;
options = defaults(options, { options = defaults(options, {
annotations : false, annotations : false,
ascii_only : false, ascii_only : false,
@@ -103,12 +101,35 @@ function OutputStream(options) {
} }
} }
var indentation = options.indent_start;
var current_col = 0; var current_col = 0;
var current_line = 1; var current_line = 1;
var current_pos = 0; var current_pos = 0;
var OUTPUT = ""; var indentation = options.indent_start;
var last;
var line_end = 0;
var line_fixed = true;
var mappings = options.source_map && [];
var mapping_name;
var mapping_token;
var might_need_space;
var might_need_semicolon;
var need_newline_indented = false;
var need_space = false;
var newline_insert = -1;
var stack;
var OUTPUT;
function reset() {
last = "";
might_need_space = false;
might_need_semicolon = false;
stack = [];
var str = OUTPUT;
OUTPUT = "";
return str;
}
reset();
var to_utf8 = options.ascii_only ? function(str, identifier) { var to_utf8 = options.ascii_only ? function(str, identifier) {
if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) { if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}"; return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}";
@@ -141,6 +162,25 @@ function OutputStream(options) {
return j == 0 ? str : s + str.slice(j); return j == 0 ? str : s + str.slice(j);
}; };
function quote_single(str) {
return "'" + str.replace(/\x27/g, "\\'") + "'";
}
function quote_double(str) {
return '"' + str.replace(/\x22/g, '\\"') + '"';
}
var quote_string = [
null,
quote_single,
quote_double,
function(str, quote) {
return quote == "'" ? quote_single(str) : quote_double(str);
},
][options.quote_style] || function(str, quote, dq, sq) {
return dq > sq ? quote_single(str) : quote_double(str);
};
function make_string(str, quote) { function make_string(str, quote) {
var dq = 0, sq = 0; var dq = 0, sq = 0;
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s, i) { str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s, i) {
@@ -162,54 +202,11 @@ function OutputStream(options) {
} }
return s; return s;
}); });
function quote_single() { return quote_string(to_utf8(str), quote, dq, sq);
return "'" + str.replace(/\x27/g, "\\'") + "'";
}
function quote_double() {
return '"' + str.replace(/\x22/g, '\\"') + '"';
}
str = to_utf8(str);
switch (options.quote_style) {
case 1:
return quote_single();
case 2:
return quote_double();
case 3:
return quote == "'" ? quote_single() : quote_double();
default:
return dq > sq ? quote_single() : quote_double();
}
}
function encode_string(str, quote) {
var ret = make_string(str, quote);
if (options.inline_script) {
ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
ret = ret.replace(/\x3c!--/g, "\\x3c!--");
ret = ret.replace(/--\x3e/g, "--\\x3e");
}
return ret;
}
function make_name(name) {
name = name.toString();
name = to_utf8(name, true);
return name;
} }
/* -----[ beautification/minification ]----- */ /* -----[ beautification/minification ]----- */
var has_parens = false;
var line_end = 0;
var line_fixed = true;
var might_need_space = false;
var might_need_semicolon = false;
var need_newline_indented = false;
var need_space = false;
var newline_insert = -1;
var last = "";
var mapping_token, mapping_name, mappings = options.source_map && [];
var adjust_mappings = mappings ? function(line, col) { var adjust_mappings = mappings ? function(line, col) {
mappings.forEach(function(mapping) { mappings.forEach(function(mapping) {
mapping.line += line; mapping.line += line;
@@ -257,8 +254,14 @@ function OutputStream(options) {
var requireSemicolonChars = makePredicate("( [ + * / - , ."); var requireSemicolonChars = makePredicate("( [ + * / - , .");
function print(str) { var print = options.beautify
str = String(str); || options.comments
|| options.max_line_len
|| options.preserve_line
|| options.shebang
|| !options.semicolons
|| options.source_map
|| options.width ? function(str) {
var ch = str.charAt(0); var ch = str.charAt(0);
if (need_newline_indented && ch) { if (need_newline_indented && ch) {
need_newline_indented = false; need_newline_indented = false;
@@ -328,7 +331,6 @@ function OutputStream(options) {
} }
OUTPUT += str; OUTPUT += str;
has_parens = str.slice(-1) == "(";
current_pos += str.length; current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1; var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n; current_line += n;
@@ -338,7 +340,30 @@ function OutputStream(options) {
current_col = a[n].length; current_col = a[n].length;
} }
last = str; last = str;
} } : function(str) {
var ch = str.charAt(0);
var prev = last.slice(-1);
if (might_need_semicolon) {
might_need_semicolon = false;
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
OUTPUT += ";";
might_need_space = false;
}
}
if (might_need_space) {
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last)
|| str == "--" && last == "!"
|| str == "in" && prev == "/"
|| last == "--" && ch == ">") {
OUTPUT += " ";
}
if (prev != "<" || str != "!") might_need_space = false;
}
OUTPUT += str;
last = str;
};
var space = options.beautify ? function() { var space = options.beautify ? function() {
print(" "); print(" ");
@@ -351,14 +376,12 @@ function OutputStream(options) {
print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation)); print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation));
} : noop; } : noop;
var with_indent = options.beautify ? function(col, cont) { var with_indent = options.beautify ? function(cont) {
if (col === true) col = next_indent();
var save_indentation = indentation; var save_indentation = indentation;
indentation = col; indentation += options.indent_level;
var ret = cont(); cont();
indentation = save_indentation; indentation = save_indentation;
return ret; } : function(cont) { cont() };
} : function(col, cont) { return cont() };
var may_add_newline = options.max_line_len || options.preserve_line ? function() { var may_add_newline = options.max_line_len || options.preserve_line ? function() {
fix_line(); fix_line();
@@ -387,41 +410,28 @@ function OutputStream(options) {
print(";"); print(";");
} }
function next_indent() {
return indentation + options.indent_level;
}
function with_block(cont) { function with_block(cont) {
var ret;
print("{"); print("{");
newline(); newline();
with_indent(next_indent(), function() { with_indent(cont);
ret = cont();
});
indent(); indent();
print("}"); print("}");
return ret;
} }
function with_parens(cont) { function with_parens(cont) {
print("("); print("(");
may_add_newline(); may_add_newline();
//XXX: still nice to have that for argument lists cont();
//var ret = with_indent(current_col, cont);
var ret = cont();
may_add_newline(); may_add_newline();
print(")"); print(")");
return ret;
} }
function with_square(cont) { function with_square(cont) {
print("["); print("[");
may_add_newline(); may_add_newline();
//var ret = with_indent(current_col, cont); cont();
var ret = cont();
may_add_newline(); may_add_newline();
print("]"); print("]");
return ret;
} }
function comma() { function comma() {
@@ -472,31 +482,37 @@ function OutputStream(options) {
return true; return true;
} }
function should_merge_comments(node, parent) {
if (parent instanceof AST_Binary) return parent.left === node;
if (parent.TYPE == "Call") return parent.expression === node;
if (parent instanceof AST_Conditional) return parent.condition === node;
if (parent instanceof AST_Dot) return parent.expression === node;
if (parent instanceof AST_Exit) return true;
if (parent instanceof AST_Sequence) return parent.expressions[0] === node;
if (parent instanceof AST_Sub) return parent.expression === node;
if (parent instanceof AST_UnaryPostfix) return true;
if (parent instanceof AST_Yield) return true;
}
function prepend_comments(node) { function prepend_comments(node) {
var self = this; var self = this;
var scan = node instanceof AST_Exit && node.value; var scan;
if (node instanceof AST_Exit) {
scan = node.value;
} else if (node instanceof AST_Yield) {
scan = node.expression;
}
var comments = dump(node); var comments = dump(node);
if (!comments) comments = []; if (!comments) comments = [];
if (scan) { if (scan) {
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
var parent = tw.parent(); if (!should_merge_comments(node, tw.parent())) return true;
if (parent instanceof AST_Exit var before = dump(node);
|| parent instanceof AST_Binary && parent.left === node if (before) comments = comments.concat(before);
|| parent.TYPE == "Call" && parent.expression === node
|| parent instanceof AST_Conditional && parent.condition === node
|| parent instanceof AST_Dot && parent.expression === node
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) {
var before = dump(node);
if (before) comments = comments.concat(before);
} else {
return true;
}
}); });
tw.push(node); tw.push(node);
node.value.walk(tw); scan.walk(tw);
} }
if (current_pos == 0) { if (current_pos == 0) {
@@ -553,15 +569,14 @@ function OutputStream(options) {
if (OUTPUT.length > insert) newline_insert = insert; if (OUTPUT.length > insert) newline_insert = insert;
} }
var stack = [];
return { return {
get : get, get : get,
toString : get, reset : reset,
indent : indent, indent : indent,
should_break : readonly ? noop : function() { should_break : options.width ? function() {
return options.width && current_col - indentation >= options.width; return current_col - indentation >= options.width;
}, } : return_false,
has_parens : function() { return has_parens }, has_parens : function() { return last.slice(-1) == "(" },
newline : newline, newline : newline,
print : print, print : print,
space : space, space : space,
@@ -571,20 +586,21 @@ function OutputStream(options) {
semicolon : semicolon, semicolon : semicolon,
force_semicolon : force_semicolon, force_semicolon : force_semicolon,
to_utf8 : to_utf8, to_utf8 : to_utf8,
print_name : function(name) { print(make_name(name)) }, print_name : function(name) { print(to_utf8(name.toString(), true)) },
print_string : function(str, quote) { print(encode_string(str, quote)) }, print_string : options.inline_script ? function(str, quote) {
next_indent : next_indent, str = make_string(str, quote).replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
print(str.replace(/\x3c!--/g, "\\x3c!--").replace(/--\x3e/g, "--\\x3e"));
} : function(str, quote) {
print(make_string(str, quote));
},
with_indent : with_indent, with_indent : with_indent,
with_block : with_block, with_block : with_block,
with_parens : with_parens, with_parens : with_parens,
with_square : with_square, with_square : with_square,
add_mapping : add_mapping, add_mapping : add_mapping,
option : function(opt) { return options[opt] }, option : function(opt) { return options[opt] },
prepend_comments: readonly ? noop : prepend_comments, prepend_comments: options.comments || options.shebang ? prepend_comments : noop,
append_comments : readonly || comment_filter === return_false ? noop : append_comments, append_comments : options.comments ? append_comments : noop,
line : function() { return current_line },
col : function() { return current_col },
pos : function() { return current_pos },
push_node : function(node) { stack.push(node) }, push_node : function(node) { stack.push(node) },
pop_node : options.preserve_line ? function() { pop_node : options.preserve_line ? function() {
var node = stack.pop(); var node = stack.pop();
@@ -629,10 +645,19 @@ function OutputStream(options) {
stream.append_comments(self); stream.append_comments(self);
} }
}); });
var readonly = OutputStream({
inline_script: false,
shebang: false,
width: false,
});
AST_Node.DEFMETHOD("print_to_string", function(options) { AST_Node.DEFMETHOD("print_to_string", function(options) {
var s = OutputStream(options); if (options) {
this.print(s); var stream = OutputStream(options);
return s.get(); this.print(stream);
return stream.get();
}
this.print(readonly);
return readonly.reset();
}); });
/* -----[ PARENTHESES ]----- */ /* -----[ PARENTHESES ]----- */
@@ -684,6 +709,8 @@ function OutputStream(options) {
// (x++)[y] // (x++)[y]
// (typeof x).y // (typeof x).y
if (p instanceof AST_PropAccess) return p.expression === this; if (p instanceof AST_PropAccess) return p.expression === this;
// (~x)`foo`
if (p instanceof AST_Template) return p.tag === this;
} }
PARENS(AST_Await, needs_parens_unary); PARENS(AST_Await, needs_parens_unary);
PARENS(AST_Unary, needs_parens_unary); PARENS(AST_Unary, needs_parens_unary);
@@ -757,14 +784,29 @@ function OutputStream(options) {
if (p instanceof AST_Class) return true; if (p instanceof AST_Class) return true;
// (foo && bar)["prop"], (foo && bar).prop // (foo && bar)["prop"], (foo && bar).prop
if (p instanceof AST_PropAccess) return p.expression === this; if (p instanceof AST_PropAccess) return p.expression === this;
// (foo && bar)``
if (p instanceof AST_Template) return p.tag === this;
// typeof (foo && bar) // typeof (foo && bar)
if (p instanceof AST_Unary) return true; if (p instanceof AST_Unary) return true;
}); });
function lhs_has_optional(node, output) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === node && is_lhs(p, output.parent(1))) {
// ++(foo?.bar).baz
// (foo?.()).bar = baz
do {
if (node.optional) return true;
node = node.expression;
} while (node.TYPE == "Call" || node instanceof AST_PropAccess);
}
}
PARENS(AST_PropAccess, function(output) { PARENS(AST_PropAccess, function(output) {
var node = this; var node = this;
var p = output.parent(); var p = output.parent();
if (p instanceof AST_New && p.expression === node) { if (p instanceof AST_New) {
if (p.expression !== node) return false;
// i.e. new (foo().bar) // i.e. new (foo().bar)
// //
// if there's one call into this subtree, then we need // if there's one call into this subtree, then we need
@@ -776,20 +818,22 @@ function OutputStream(options) {
} while (node instanceof AST_PropAccess); } while (node instanceof AST_PropAccess);
return node.TYPE == "Call"; return node.TYPE == "Call";
} }
return lhs_has_optional(node, output);
}); });
PARENS(AST_Call, function(output) { PARENS(AST_Call, function(output) {
var node = this;
var p = output.parent(); var p = output.parent();
if (p instanceof AST_New) return p.expression === this; if (p instanceof AST_New) return p.expression === node;
// https://bugs.webkit.org/show_bug.cgi?id=123506 // https://bugs.webkit.org/show_bug.cgi?id=123506
if (output.option("webkit")) { if (output.option("webkit")
&& node.expression instanceof AST_Function
&& p instanceof AST_PropAccess
&& p.expression === node) {
var g = output.parent(1); var g = output.parent(1);
return this.expression instanceof AST_Function if (g instanceof AST_Assign && g.left === p) return true;
&& p instanceof AST_PropAccess
&& p.expression === this
&& g instanceof AST_Assign
&& g.left === p;
} }
return lhs_has_optional(node, output);
}); });
PARENS(AST_New, function(output) { PARENS(AST_New, function(output) {
@@ -915,7 +959,7 @@ function OutputStream(options) {
}); });
function print_braced_empty(self, output) { function print_braced_empty(self, output) {
output.print("{"); output.print("{");
output.with_indent(output.next_indent(), function() { output.with_indent(function() {
output.append_comments(self, true); output.append_comments(self, true);
}); });
output.print("}"); output.print("}");
@@ -1431,7 +1475,7 @@ function OutputStream(options) {
parent = output.parent(level++); parent = output.parent(level++);
if (parent instanceof AST_Call && parent.expression === node) return; if (parent instanceof AST_Call && parent.expression === node) return;
} while (parent instanceof AST_PropAccess && parent.expression === node); } while (parent instanceof AST_PropAccess && parent.expression === node);
output.print("/*" + self.pure + "*/"); output.print(typeof self.pure == "string" ? "/*" + self.pure + "*/" : "/*@__PURE__*/");
} }
function print_call_args(self, output) { function print_call_args(self, output) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
@@ -1448,6 +1492,7 @@ function OutputStream(options) {
var self = this; var self = this;
print_annotation(self, output); print_annotation(self, output);
self.expression.print(output); self.expression.print(output);
if (self.optional) output.print("?.");
print_call_args(self, output); print_call_args(self, output);
}); });
DEFPRINT(AST_New, function(output) { DEFPRINT(AST_New, function(output) {
@@ -1476,26 +1521,23 @@ function OutputStream(options) {
expr.print(output); expr.print(output);
var prop = self.property; var prop = self.property;
if (output.option("ie8") && RESERVED_WORDS[prop]) { if (output.option("ie8") && RESERVED_WORDS[prop]) {
output.print("["); output.print(self.optional ? "?.[" : "[");
output.add_mapping(self.end); output.add_mapping(self.end);
output.print_string(prop); output.print_string(prop);
output.print("]"); output.print("]");
} else { } else {
if (expr instanceof AST_Number && expr.value >= 0) { if (expr instanceof AST_Number && !/[ex.)]/i.test(output.last())) output.print(".");
if (!/[xa-f.)]/i.test(output.last())) { output.print(self.optional ? "?." : ".");
output.print(".");
}
}
output.print(".");
// the name after dot would be mapped about here. // the name after dot would be mapped about here.
output.add_mapping(self.end); output.add_mapping(self.end);
output.print_name(prop); output.print_name(prop);
} }
}); });
DEFPRINT(AST_Sub, function(output) { DEFPRINT(AST_Sub, function(output) {
this.expression.print(output); var self = this;
output.print("["); self.expression.print(output);
this.property.print(output); output.print(self.optional ? "?.[" : "[");
self.property.print(output);
output.print("]"); output.print("]");
}); });
DEFPRINT(AST_Spread, function(output) { DEFPRINT(AST_Spread, function(output) {
@@ -1735,7 +1777,7 @@ function OutputStream(options) {
output.print("`"); output.print("`");
}); });
DEFPRINT(AST_Constant, function(output) { DEFPRINT(AST_Constant, function(output) {
output.print(this.value); output.print("" + this.value);
}); });
DEFPRINT(AST_String, function(output) { DEFPRINT(AST_String, function(output) {
output.print_string(this.value, this.quote); output.print_string(this.value, this.quote);
@@ -1791,7 +1833,7 @@ function OutputStream(options) {
function force_statement(stat, output) { function force_statement(stat, output) {
if (output.option("braces") && !(stat instanceof AST_Const || stat instanceof AST_Let)) { if (output.option("braces") && !(stat instanceof AST_Const || stat instanceof AST_Let)) {
make_block(stat, output); make_block(stat, output);
} else if (!stat || stat instanceof AST_EmptyStatement) { } else if (stat instanceof AST_EmptyStatement) {
output.force_semicolon(); output.force_semicolon();
} else { } else {
stat.print(output); stat.print(output);
@@ -1842,11 +1884,11 @@ function OutputStream(options) {
} }
function make_block(stmt, output) { function make_block(stmt, output) {
if (!stmt || stmt instanceof AST_EmptyStatement) if (stmt instanceof AST_EmptyStatement) {
output.print("{}"); print_braced_empty(stmt, output);
else if (stmt instanceof AST_BlockStatement) } else if (stmt instanceof AST_BlockStatement) {
stmt.print(output); stmt.print(output);
else output.with_block(function() { } else output.with_block(function() {
output.indent(); output.indent();
stmt.print(output); stmt.print(output);
output.newline(); output.newline();
@@ -1893,7 +1935,11 @@ function OutputStream(options) {
output.add_mapping(this.start); output.add_mapping(this.start);
}); });
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) { DEFMAP([
AST_ClassProperty,
AST_DestructuredKeyVal,
AST_ObjectProperty,
], function(output) {
if (typeof this.key == "string") output.add_mapping(this.start, this.key); if (typeof this.key == "string") output.add_mapping(this.start, this.key);
}); });
})(); })();

View File

@@ -124,7 +124,7 @@ var PUNC_AFTER_EXPRESSION = PUNC_SEPARATORS + PUNC_CLOSERS;
var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS; var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS;
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS; var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS;
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF"; var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS)); var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"#" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS)); NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS)); OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
@@ -351,7 +351,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function read_while(pred) { function read_while(pred) {
var ret = "", ch; var ret = "", ch;
while ((ch = peek()) && pred(ch)) ret += next(); while ((ch = peek()) && pred(ch, ret)) ret += next();
return ret; return ret;
} }
@@ -359,24 +359,27 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
js_error(err, filename, S.tokline, S.tokcol, S.tokpos); js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
} }
function is_octal(num) {
return /^0[0-7_]+$/.test(num);
}
function read_num(prefix) { function read_num(prefix) {
var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
var num = read_while(function(ch) { var num = read_while(function(ch, str) {
var code = ch.charCodeAt(0); switch (ch) {
switch (code) { case "x": case "X":
case 120: case 88: // xX
return has_x ? false : (has_x = true); return has_x ? false : (has_x = true);
case 101: case 69: // eE case "e": case "E":
return has_x ? true : has_e ? false : (has_e = after_e = true); return has_x ? true : has_e ? false : (has_e = after_e = true);
case 43: case 45: // +- case "+": case "-":
return after_e; return after_e;
case (after_e = false, 46): // . case (after_e = false, "."):
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false; return has_dot || has_e || has_x || is_octal(str) ? false : (has_dot = true);
} }
return is_digit(code) || /[_0-9a-fo]/i.test(ch); return /[_0-9a-dfo]/i.test(ch);
}); });
if (prefix) num = prefix + num; if (prefix) num = prefix + num;
if (/^0[0-7_]+$/.test(num)) { if (is_octal(num)) {
if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode"); if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode");
} else { } else {
num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1"); num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1");
@@ -465,7 +468,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}); });
function read_name() { function read_name() {
var backslash = false, name = "", ch, escaped = false, hex; var backslash = false, ch, escaped = false, name = peek() == "#" ? next() : "";
while (ch = peek()) { while (ch = peek()) {
if (!backslash) { if (!backslash) {
if (ch == "\\") escaped = backslash = true, next(); if (ch == "\\") escaped = backslash = true, next();
@@ -480,7 +483,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
} }
if (KEYWORDS[name] && escaped) { if (KEYWORDS[name] && escaped) {
hex = name.charCodeAt(0).toString(16).toUpperCase(); var hex = name.charCodeAt(0).toString(16).toUpperCase();
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
} }
return name; return name;
@@ -615,7 +618,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (PUNC_CHARS[ch]) return token("punc", next()); if (PUNC_CHARS[ch]) return token("punc", next());
if (looking_at("=>")) return token("punc", next() + next()); if (looking_at("=>")) return token("punc", next() + next());
if (OPERATOR_CHARS[ch]) return read_operator(); if (OPERATOR_CHARS[ch]) return read_operator();
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word(); if (code == 35 || code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
break; break;
} }
parse_error("Unexpected character '" + ch + "'"); parse_error("Unexpected character '" + ch + "'");
@@ -854,7 +857,8 @@ function parse($TEXT, options) {
next(); next();
return export_(); return export_();
case "import": case "import":
if (!is_token(peek(), "punc", "(")) { var token = peek();
if (!(token.type == "punc" && /^[(.]$/.test(token.value))) {
next(); next();
return import_(); return import_();
} }
@@ -1185,7 +1189,7 @@ function parse($TEXT, options) {
var await = is("name", "await") && next(); var await = is("name", "await") && next();
expect("("); expect("(");
var init = null; var init = null;
if (!is("punc", ";")) { if (await || !is("punc", ";")) {
init = is("keyword", "const") init = is("keyword", "const")
? (next(), const_(true)) ? (next(), const_(true))
: is("keyword", "let") : is("keyword", "let")
@@ -1236,6 +1240,7 @@ function parse($TEXT, options) {
} }
function for_enum(ctor, init) { function for_enum(ctor, init) {
handle_regexp();
var obj = expression(); var obj = expression();
expect(")"); expect(")");
return new ctor({ return new ctor({
@@ -1329,21 +1334,19 @@ function parse($TEXT, options) {
if (is("punc", "{")) { if (is("punc", "{")) {
body = block_(); body = block_();
value = null; value = null;
if (S.input.has_directive("use strict")) {
argnames.forEach(strict_verify_symbol);
}
} else { } else {
body = []; body = [];
handle_regexp(); handle_regexp();
value = maybe_assign(); value = maybe_assign();
} }
var is_strict = S.input.has_directive("use strict");
S.input.pop_directives_stack(); S.input.pop_directives_stack();
--S.in_function; --S.in_function;
S.in_loop = loop; S.in_loop = loop;
S.labels = labels; S.labels = labels;
S.in_generator = was_gen; S.in_generator = was_gen;
S.in_async = was_async; S.in_async = was_async;
return new (async ? AST_AsyncArrow : AST_Arrow)({ var node = new (async ? AST_AsyncArrow : AST_Arrow)({
start: start, start: start,
argnames: argnames, argnames: argnames,
rest: rest, rest: rest,
@@ -1351,6 +1354,8 @@ function parse($TEXT, options) {
value: value, value: value,
end: prev(), end: prev(),
}); });
if (is_strict) node.each_argname(strict_verify_symbol);
return node;
} }
var function_ = function(ctor) { var function_ = function(ctor) {
@@ -1383,23 +1388,24 @@ function parse($TEXT, options) {
S.in_loop = 0; S.in_loop = 0;
S.labels = []; S.labels = [];
var body = block_(); var body = block_();
if (S.input.has_directive("use strict")) { var is_strict = S.input.has_directive("use strict");
if (name) strict_verify_symbol(name);
argnames.forEach(strict_verify_symbol);
if (argnames.rest) strict_verify_symbol(argnames.rest);
}
S.input.pop_directives_stack(); S.input.pop_directives_stack();
--S.in_function; --S.in_function;
S.in_loop = loop; S.in_loop = loop;
S.labels = labels; S.labels = labels;
S.in_generator = was_gen; S.in_generator = was_gen;
S.in_async = was_async; S.in_async = was_async;
return new ctor({ var node = new ctor({
name: name, name: name,
argnames: argnames, argnames: argnames,
rest: argnames.rest || null, rest: argnames.rest || null,
body: body body: body
}); });
if (is_strict) {
if (name) strict_verify_symbol(name);
node.each_argname(strict_verify_symbol);
}
return node;
}; };
function if_() { function if_() {
@@ -1491,6 +1497,7 @@ function parse($TEXT, options) {
body.start = start; body.start = start;
body.end = prev(); body.end = prev();
} else { } else {
handle_regexp();
body = expression(); body = expression();
semicolon(); semicolon();
} }
@@ -2239,44 +2246,52 @@ function parse($TEXT, options) {
}); });
} }
var subscripts = function(expr, allow_calls) { var subscripts = function(expr, allow_calls, optional) {
var start = expr.start; var start = expr.start;
if (is("punc", ".")) {
next();
return subscripts(new AST_Dot({
start : start,
expression : expr,
property : as_name(),
end : prev()
}), allow_calls);
}
if (is("punc", "[")) { if (is("punc", "[")) {
next(); next();
var prop = expression(); var prop = expression();
expect("]"); expect("]");
return subscripts(new AST_Sub({ return subscripts(new AST_Sub({
start : start, start: start,
expression : expr, optional: optional,
property : prop, expression: expr,
end : prev() property: prop,
end: prev(),
}), allow_calls); }), allow_calls);
} }
if (allow_calls && is("punc", "(")) { if (allow_calls && is("punc", "(")) {
next(); next();
var call = new AST_Call({ var call = new AST_Call({
start : start, start: start,
expression : expr, optional: optional,
args : expr_list(")", !options.strict), expression: expr,
end : prev() args: expr_list(")", !options.strict),
end: prev(),
}); });
return subscripts(call, true); return subscripts(call, true);
} }
if (optional || is("punc", ".")) {
if (!optional) next();
return subscripts(new AST_Dot({
start: start,
optional: optional,
expression: expr,
property: as_name(),
end: prev(),
}), allow_calls);
}
if (is("punc", "`")) { if (is("punc", "`")) {
var tmpl = template(expr); var tmpl = template(expr);
tmpl.start = expr.start; tmpl.start = expr.start;
tmpl.end = prev(); tmpl.end = prev();
return subscripts(tmpl, allow_calls); return subscripts(tmpl, allow_calls);
} }
if (is("operator", "?") && is_token(peek(), "punc", ".")) {
next();
next();
return subscripts(expr, allow_calls, true);
}
if (expr instanceof AST_Call && !expr.pure) { if (expr instanceof AST_Call && !expr.pure) {
var start = expr.start; var start = expr.start;
var comments = start.comments_before; var comments = start.comments_before;
@@ -2399,7 +2414,7 @@ function parse($TEXT, options) {
}; };
function is_assignable(expr) { function is_assignable(expr) {
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; return expr instanceof AST_PropAccess && !expr.optional || expr instanceof AST_SymbolRef;
} }
function to_destructured(node) { function to_destructured(node) {
@@ -2521,7 +2536,7 @@ function parse($TEXT, options) {
while (!is("eof")) while (!is("eof"))
body.push(statement()); body.push(statement());
S.input.pop_directives_stack(); S.input.pop_directives_stack();
var end = prev(); var end = prev() || start;
var toplevel = options.toplevel; var toplevel = options.toplevel;
if (toplevel) { if (toplevel) {
toplevel.body = toplevel.body.concat(body); toplevel.body = toplevel.body.concat(body);

View File

@@ -81,7 +81,9 @@ var builtins = function() {
function reserve_quoted_keys(ast, reserved) { function reserve_quoted_keys(ast, reserved) {
ast.walk(new TreeWalker(function(node) { ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectProperty) { 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.start && node.start.quote) add(node.key);
} else if (node instanceof AST_Sub) { } else if (node instanceof AST_Sub) {
addStrings(node.property, add); addStrings(node.property, add);
@@ -163,6 +165,8 @@ function mangle_properties(ast, options) {
addStrings(node.args[0], add); addStrings(node.args[0], add);
break; break;
} }
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") add(node.key);
} else if (node instanceof AST_Dot) { } else if (node instanceof AST_Dot) {
add(node.property); add(node.property);
} else if (node instanceof AST_ObjectProperty) { } else if (node instanceof AST_ObjectProperty) {
@@ -193,6 +197,8 @@ function mangle_properties(ast, options) {
mangleStrings(node.args[0]); mangleStrings(node.args[0]);
break; break;
} }
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_Dot) { } else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} else if (node instanceof AST_ObjectProperty) { } else if (node instanceof AST_ObjectProperty) {
@@ -222,9 +228,7 @@ function mangle_properties(ast, options) {
} }
function mangle(name) { function mangle(name) {
if (!should_mangle(name)) { if (!should_mangle(name)) return name;
return name;
}
var mangled = cache.get(name); var mangled = cache.get(name);
if (!mangled) { if (!mangled) {
if (debug) { if (debug) {
@@ -236,6 +240,7 @@ function mangle_properties(ast, options) {
if (!mangled) do { if (!mangled) do {
mangled = base54(++cname); mangled = base54(++cname);
} while (!can_mangle(mangled)); } while (!can_mangle(mangled));
if (/^#/.test(name)) mangled = "#" + mangled;
cache.set(name, mangled); cache.set(name, mangled);
} }
return mangled; return mangled;

View File

@@ -80,15 +80,16 @@ SymbolDef.prototype = {
} }
}, },
redefined: function() { redefined: function() {
var scope = this.defun; var self = this;
var scope = self.defun;
if (!scope) return; if (!scope) return;
var name = this.name; var name = self.name;
var def = scope.variables.get(name) var def = scope.variables.get(name)
|| scope instanceof AST_Toplevel && scope.globals.get(name) || scope instanceof AST_Toplevel && scope.globals.get(name)
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) { || self.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
return def.name == name; return def.name == name;
}, scope.enclosed); }, scope.enclosed);
if (def && def !== this) return def.redefined() || def; if (def && def !== self) return def.redefined() || def;
}, },
unmangleable: function(options) { unmangleable: function(options) {
return this.global && !options.toplevel return this.global && !options.toplevel
@@ -273,16 +274,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
return true; return true;
} }
if (node instanceof AST_SymbolDeclaration) { if (node instanceof AST_SymbolDeclaration) {
var def = node.definition();
def.preinit = def.references.length;
if (node instanceof AST_SymbolCatch) { if (node instanceof AST_SymbolCatch) {
// ensure mangling works if `catch` reuses a scope variable // ensure mangling works if `catch` reuses a scope variable
var def = node.definition().redefined(); var redef = def.redefined();
if (def) for (var s = node.scope; s; s = s.parent_scope) { if (redef) for (var s = node.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def); push_uniq(s.enclosed, redef);
if (s === def.scope) break; if (s === redef.scope) break;
} }
} else if (node instanceof AST_SymbolConst) { } else if (node instanceof AST_SymbolConst) {
// ensure compression works if `const` reuses a scope variable // ensure compression works if `const` reuses a scope variable
var redef = node.definition().redefined(); var redef = def.redefined();
if (redef) redef.const_redefs = true; if (redef) redef.const_redefs = true;
} }
if (node.name != "arguments") return true; if (node.name != "arguments") return true;
@@ -394,13 +397,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
} else { } else {
new_def = scope.def_variable(node); new_def = scope.def_variable(node);
} }
if (new_def.undeclared) self.variables.set(name, new_def);
if (name == "arguments" && is_arguments(old_def) && node instanceof AST_SymbolLambda) return true;
old_def.defun = new_def.scope; old_def.defun = new_def.scope;
old_def.forEach(function(node) { old_def.forEach(function(node) {
node.redef = old_def; node.redef = old_def;
node.thedef = new_def; node.thedef = new_def;
node.reference(options); node.reference(options);
}); });
if (new_def.undeclared) self.variables.set(name, new_def);
return true; return true;
} }
}); });
@@ -798,6 +802,7 @@ var base54 = (function() {
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"); var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
var chars, frequency; var chars, frequency;
function reset() { function reset() {
chars = null;
frequency = Object.create(freq); frequency = Object.create(freq);
} }
base54.consider = function(str, delta) { base54.consider = function(str, delta) {
@@ -809,19 +814,15 @@ var base54 = (function() {
return frequency[b] - frequency[a]; return frequency[b] - frequency[a];
} }
base54.sort = function() { base54.sort = function() {
chars = leading.sort(compare).concat(digits.sort(compare)); chars = leading.sort(compare).concat(digits).sort(compare);
}; };
base54.reset = reset; base54.reset = reset;
reset(); reset();
function base54(num) { function base54(num) {
var ret = "", base = 54; var ret = leading[num % 54];
num++; for (num = Math.floor(num / 54); --num >= 0; num >>= 6) {
do { ret += chars[num & 0x3F];
num--; }
ret += chars[num % base];
num = Math.floor(num / base);
base = 64;
} while (num > 0);
return ret; return ret;
} }
return base54; return base54;

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.13.3", "version": "3.13.10",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -23,7 +23,7 @@
"LICENSE" "LICENSE"
], ],
"devDependencies": { "devDependencies": {
"acorn": "~7.1.0", "acorn": "~8.2.1",
"semver": "~6.3.0" "semver": "~6.3.0"
}, },
"scripts": { "scripts": {

View File

@@ -16,7 +16,7 @@ var urls = [
"https://code.angularjs.org/1.7.8/angular.js", "https://code.angularjs.org/1.7.8/angular.js",
"https://unpkg.com/mathjs@6.2.3/dist/math.js", "https://unpkg.com/mathjs@6.2.3/dist/math.js",
"https://unpkg.com/react@15.3.2/dist/react.js", "https://unpkg.com/react@15.3.2/dist/react.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.js", "https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js", "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js", "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js",

View File

@@ -256,6 +256,7 @@ issue_3858: {
collapse_vars: true, collapse_vars: true,
inline: true, inline: true,
keep_fargs: false, keep_fargs: false,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {

View File

@@ -254,6 +254,25 @@ duplicate_argname: {
expect_stdout: "bar 42 foo 42 bar" expect_stdout: "bar 42 foo 42 bar"
} }
fraction: {
options = {
arguments: true,
keep_fargs: false,
reduce_vars: true,
}
input: {
console.log(function() {
return arguments[0.3];
}("FAIL") || "PASS");
}
expect: {
console.log(function() {
return arguments[0.3];
}("FAIL") || "PASS");
}
expect_stdout: "PASS"
}
issue_3273: { issue_3273: {
options = { options = {
arguments: true, arguments: true,

View File

@@ -421,6 +421,7 @@ collapse_value: {
arrows: true, arrows: true,
collapse_vars: true, collapse_vars: true,
keep_fargs: false, keep_fargs: false,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {

View File

@@ -672,3 +672,77 @@ issue_4827_3: {
expect_stdout: "undefined" expect_stdout: "undefined"
node_version: ">=15" node_version: ">=15"
} }
issue_4876: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
try {
var a = null;
var b = a &&= 42;
b.p;
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
var a = null;
var b = a &&= 42;
b.p;
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4924_1: {
options = {
collapse_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a, b;
console.log("PASS");
a = function() {};
b = function() {}(b ||= a);
}
expect: {
var b;
console.log("PASS");
b = void (b ||= function() {});
}
expect_stdout: "PASS"
node_version: ">=15"
}
issue_4924_2: {
options = {
collapse_vars: true,
dead_code: true,
passes: 2,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a, b;
console.log("PASS");
a = function() {};
b = function() {}(b ||= a);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=15"
}

View File

@@ -227,9 +227,7 @@ inline_await_1_trim: {
console.log("PASS"); console.log("PASS");
} }
expect: { expect: {
(async function() { void 0;
await 0;
})();
console.log("PASS"); console.log("PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@@ -334,7 +332,7 @@ inline_await_3_trim: {
} }
expect: { expect: {
(async function() { (async function() {
return a = "PASS", b = console.log, await b(a); return a = "PASS", b = console.log, b(a);
var a, b; var a, b;
})(); })();
} }
@@ -557,6 +555,51 @@ collapse_property_lambda: {
node_version: ">=8" node_version: ">=8"
} }
drop_async_1: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
console.log(function(a) {
(async function() {
a *= 7;
})();
return a;
}(6));
}
expect: {
console.log(function(a) {
void (a *= 7);
return a;
}(6));
}
expect_stdout: "42"
node_version: ">=8"
}
drop_async_2: {
options = {
awaits: true,
collapse_vars: true,
evaluate: true,
inline: true,
side_effects: true,
}
input: {
console.log(function(a) {
(async b => await (a *= b))(7);
return a;
}(6));
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=8"
}
drop_return: { drop_return: {
options = { options = {
side_effects: true, side_effects: true,
@@ -1531,3 +1574,452 @@ issue_4764_3: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=8" node_version: ">=8"
} }
issue_4972_1: {
options = {
awaits: true,
side_effects: true,
}
input: {
console.log("foo");
(async function() {
try {
return await "bar";
} finally {
console.log("baz");
}
})().then(console.log);
console.log("moo");
}
expect: {
console.log("foo");
(async function() {
try {
return await "bar";
} finally {
console.log("baz");
}
})().then(console.log);
console.log("moo");
}
expect_stdout: [
"foo",
"moo",
"baz",
"bar",
]
node_version: ">=8"
}
issue_4972_2: {
options = {
awaits: true,
side_effects: true,
}
input: {
console.log("foo");
(async function() {
try {
console.log("bar");
} finally {
return await "baz";
}
})().then(console.log);
console.log("moo");
}
expect: {
console.log("foo");
(async function() {
try {
console.log("bar");
} finally {
return "baz";
}
})().then(console.log);
console.log("moo");
}
expect_stdout: [
"foo",
"bar",
"moo",
"baz",
]
node_version: ">=8"
}
issue_4972_3: {
options = {
awaits: true,
side_effects: true,
}
input: {
console.log("foo");
try {
(async function() {
return await "bar";
})().then(console.log);
} finally {
console.log("baz");
}
console.log("moo");
}
expect: {
console.log("foo");
try {
(async function() {
return "bar";
})().then(console.log);
} finally {
console.log("baz");
}
console.log("moo");
}
expect_stdout: [
"foo",
"baz",
"moo",
"bar",
]
node_version: ">=8"
}
issue_4974: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function f() {
return 42 in f();
})();
console.log("PASS");
}
expect: {
(async function f() {
return 42 in f();
})();
console.log("PASS");
}
expect_stdout: true
node_version: ">=8"
}
issue_4975: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function f(a) {
try {
if (a) console.log(typeof f());
} catch (e) {}
})(42);
}
expect: {
(async function f(a) {
try {
if (a) console.log(typeof f());
} catch (e) {}
})(42);
}
expect_stdout: "object"
node_version: ">=8"
}
issue_4987: {
options = {
awaits: true,
side_effects: true,
}
input: {
(async function() {
try {
await 42;
} finally {
console.log("foo");
}
})();
console.log("bar");
}
expect: {
(async function() {
try {
await 0;
} finally {
console.log("foo");
}
})();
console.log("bar");
}
expect_stdout: [
"bar",
"foo",
]
node_version: ">=8"
}
issue_5001: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = 0;
(async function() {
a++ | await 42;
})();
console.log(a ? "PASS" : "FAIL");
}
expect: {
var a = 0;
void a++;
console.log(a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5019_1: {
options = {
dead_code: true,
}
input: {
(function(a) {
(async function() {
await 42;
console.log(a);
})();
a = "PASS";
})("FAIL");
}
expect: {
(function(a) {
(async function() {
await 42;
console.log(a);
})();
a = "PASS";
})("FAIL");
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5019_2: {
options = {
dead_code: true,
}
input: {
console.log("sync", function(a) {
(async function() {
console.log(await "async", a);
})();
return a = "PASS";
}("FAIL"));
}
expect: {
console.log("sync", function(a) {
(async function() {
console.log(await "async", a);
})();
return a = "PASS";
}("FAIL"));
}
expect_stdout: [
"sync PASS",
"async PASS",
]
node_version: ">=8"
}
issue_5019_3: {
options = {
inline: true,
toplevel: true,
}
input: {
for (var i in "foo") {
(function(a) {
(async function() {
console.log(await "async", a);
})();
})(i);
console.log("sync", i);
}
}
expect: {
for (var i in "foo") {
(function(a) {
(async function() {
console.log(await "async", a);
})();
})(i);
console.log("sync", i);
}
}
expect_stdout: [
"sync 0",
"sync 1",
"sync 2",
"async 0",
"async 1",
"async 2",
]
node_version: ">=8"
}
issue_5023_1: {
options = {
awaits: true,
reduce_vars: true,
side_effects: true,
}
input: {
(async function() {
let a = a;
})();
console.log("PASS");
}
expect: {
(async function() {
let a = a;
})();
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5023_2: {
options = {
awaits: true,
reduce_vars: true,
side_effects: true,
}
input: {
(async function() {
let a;
a = a;
})();
console.log("PASS");
}
expect: {
(function() {
let a;
a = a;
})();
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5032_normal: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(c) {
var b = log(c), c = b;
log(b);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5032_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5034: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var await = function f() {
return async function() {
return f;
};
};
await()().then(function(value) {
console.log(value === await ? "PASS" : "FAIL");
});
})();
}
expect: {
(function() {
var await = function f() {
return async function() {
return f;
};
};
await()().then(function(value) {
console.log(value === await ? "PASS" : "FAIL");
});
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}

View File

@@ -29,6 +29,383 @@ iife_boolean_context: {
] ]
} }
de_morgan_1a: {
options = {
booleans: true,
}
input: {
function f(a) {
return a || a;
}
console.log(f(null), f(42));
}
expect: {
function f(a) {
return a;
}
console.log(f(null), f(42));
}
expect_stdout: "null 42"
}
de_morgan_1b: {
options = {
booleans: true,
}
input: {
function f(a) {
return a && a;
}
console.log(f(null), f(42));
}
expect: {
function f(a) {
return a;
}
console.log(f(null), f(42));
}
expect_stdout: "null 42"
}
de_morgan_1c: {
options = {
booleans: true,
}
input: {
console.log(delete (NaN && NaN));
}
expect: {
console.log(delete (0, NaN));
}
expect_stdout: "true"
}
de_morgan_2a: {
options = {
booleans: true,
conditionals: true,
}
input: {
function f(a, b) {
return a || (a || 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: [
"undefined {}",
"42 42",
]
}
de_morgan_2b: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b) {
return a || (a && b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"42 42",
]
}
de_morgan_2c: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b) {
return a && (a || b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"42 42",
]
}
de_morgan_2d: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b) {
return a && (a && 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,
conditionals: true,
}
input: {
function f(a, b, c) {
return a || ((a || b) || c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a || b || c;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"undefined {} true true",
"42 42 42 42",
]
}
de_morgan_3b: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b, c) {
return a || ((a || b) && c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a || b && c;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"false false undefined {}",
"42 42 42 42",
]
}
de_morgan_3c: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b, c) {
return a || ((a && b) || c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a || c;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"undefined {} undefined {}",
"42 42 42 42",
]
}
de_morgan_3d: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b, c) {
return a || ((a && b) && c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"null null null null",
"42 42 42 42",
]
}
de_morgan_3e: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b, c) {
return a && ((a || b) || c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"null null null null",
"42 42 42 42",
]
}
de_morgan_3f: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b, c) {
return a && ((a || b) && c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a && c;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"null null null null",
"undefined {} undefined {}",
]
}
de_morgan_3g: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b, c) {
return a && ((a && b) || c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a && (b || c);
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"null null null null",
"undefined {} true true",
]
}
de_morgan_3h: {
options = {
booleans: true,
conditionals: true,
}
input: {
function f(a, b, c) {
return a && ((a && b) && c);
}
console.log(f(null, false), f(null, false, {}), f(null, true), f(null, true, {}));
console.log(f(42, false), f(42, false, {}), f(42, true), f(42, true, {}));
}
expect: {
function f(a, b, c) {
return a && b && c;
}
console.log(f(null, !1), f(null, !1, {}), f(null, !0), f(null, !0, {}));
console.log(f(42, !1), f(42, !1, {}), f(42, !0), f(42, !0, {}));
}
expect_stdout: [
"null null null null",
"false false undefined {}",
]
}
conditional_chain: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
}
input: {
function f(a, b) {
return a ? a : b ? b : 42;
}
console.log(f("PASS", "FAIL"));
}
expect: {
function f(a, b) {
return a || b || 42;
}
console.log(f("PASS", "FAIL"));
}
expect_stdout: "PASS"
}
issue_3465_1: { issue_3465_1: {
options = { options = {
booleans: true, booleans: true,
@@ -181,3 +558,79 @@ issue_4374: {
} }
expect_stdout: "0" expect_stdout: "0"
} }
issue_5028_1: {
options = {
booleans: true,
conditionals: true,
}
input: {
var a = 1;
console.log(function() {
return a-- ? a-- ? "FAIL 1" : "PASS" : "FAIL 2";
}());
}
expect: {
var a = 1;
console.log(function() {
return a-- ? a-- ? "FAIL 1" : "PASS" : "FAIL 2";
}());
}
expect_stdout: "PASS"
}
issue_5028_2: {
options = {
booleans: true,
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
var a = 1;
(function() {
if (a--)
if (a--)
a = "FAIL";
else
return;
})();
console.log(a);
}
expect: {
var a = 1;
(function() {
a-- && a-- && (a = "FAIL");
})();
console.log(a);
}
expect_stdout: "-1"
}
issue_5028_3: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
if_return: true,
}
input: {
var a = 1;
(function() {
if (a--)
if (a--)
a = "FAIL";
else
return;
})();
console.log(a);
}
expect: {
var a = 1;
(function() {
a-- && a-- && (a = "FAIL");
})();
console.log(a);
}
expect_stdout: "-1"
}

View File

@@ -72,7 +72,7 @@ fields: {
console.log(k, o[k]); console.log(k, o[k]);
console.log(o.q); console.log(o.q);
} }
expect_exact: 'var o=new class A{"#p";static #p="PASS";async;get q(){return A.#p}[6*7]=console?"foo":"bar"};for(var k in o)console.log(k,o[k]);console.log(o.q);' expect_exact: 'var o=new class A{"#p";static#p="PASS";async;get q(){return A.#p}[6*7]=console?"foo":"bar"};for(var k in o)console.log(k,o[k]);console.log(o.q);'
expect_stdout: [ expect_stdout: [
"42 foo", "42 foo",
"#p undefined", "#p undefined",
@@ -136,7 +136,7 @@ private_methods: {
} }
}().q.then(console.log); }().q.then(console.log);
} }
expect_exact: "(new class A{static*#f(){yield 3*A.#p}async #g(){for(var a of A.#f())return a*await 2}static get #p(){return 7}get q(){return this.#g()}}).q.then(console.log);" expect_exact: "(new class A{static*#f(){yield 3*A.#p}async#g(){for(var a of A.#f())return a*await 2}static get#p(){return 7}get q(){return this.#g()}}).q.then(console.log);"
expect_stdout: "42" expect_stdout: "42"
node_version: ">=14.6" node_version: ">=14.6"
} }
@@ -260,6 +260,9 @@ block_scoped: {
expect: { expect: {
"use strict"; "use strict";
0; 0;
{
class A {}
}
if (console) { if (console) {
class B {} class B {}
} }
@@ -269,6 +272,38 @@ block_scoped: {
node_version: ">=4" node_version: ">=4"
} }
retain_declaration: {
options = {
dead_code: true,
}
input: {
"use strict";
var a = "FAIL";
try {
console.log(function() {
return a;
class a {}
}());
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
var a = "FAIL";
try {
console.log(function() {
return a;
class a {}
}());
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
drop_extends: { drop_extends: {
options = { options = {
inline: true, inline: true,
@@ -583,6 +618,31 @@ single_use_6: {
node_version: ">=4" node_version: ">=4"
} }
single_use_7: {
options = {
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {
static foo() {}
}
var a = "foo" in A;
console.log(a);
}
expect: {
"use strict";
console.log("foo" in class {
static foo() {}
});
}
expect_stdout: "true"
node_version: ">=4"
}
collapse_non_strict: { collapse_non_strict: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -607,6 +667,7 @@ collapse_non_strict: {
collapse_rhs: { collapse_rhs: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unsafe: true,
} }
input: { input: {
"use strict"; "use strict";
@@ -654,6 +715,32 @@ collapse_rhs_static: {
node_version: ">=12" node_version: ">=12"
} }
self_comparison: {
options = {
booleans: true,
comparisons: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
console.log(A == A, A != A);
console.log(A === A, A !== A);
}
expect: {
"use strict";
console.log(!0, !1);
console.log(!0, !1);
}
expect_stdout: [
"true false",
"true false",
]
node_version: ">=4"
}
property_side_effects: { property_side_effects: {
options = { options = {
inline: true, inline: true,
@@ -726,7 +813,7 @@ unused_await: {
})(); })();
} }
expect_stdout: true expect_stdout: true
node_version: ">=12" node_version: ">=12 <16"
} }
computed_key_side_effects: { computed_key_side_effects: {
@@ -886,9 +973,9 @@ issue_4681: {
} }
expect: { expect: {
console.log(function(a) { console.log(function(a) {
class A { (class {
static p = a = this; static p = a = this;
} });
return typeof a; return typeof a;
}()); }());
} }
@@ -1312,9 +1399,9 @@ issue_4821_1: {
} }
expect: { expect: {
var a; var a;
class A { (class {
static p = void (a = this); static p = void (a = this);
} });
console.log(typeof a); console.log(typeof a);
} }
expect_stdout: "function" expect_stdout: "function"
@@ -1344,3 +1431,447 @@ issue_4821_2: {
expect_stdout: "function" expect_stdout: "function"
node_version: ">=12" node_version: ">=12"
} }
issue_4829_1: {
options = {
properties: true,
}
input: {
"use strict";
try {
class A extends { f(){} }.f {}
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
try {
class A extends [ () => {} ][0] {}
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4829_2: {
options = {
properties: true,
}
input: {
"use strict";
try {
class A extends {
f() {
return arguments;
},
}.f {}
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
try {
class A extends {
f() {
return arguments;
},
}.f {}
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
mangle_properties: {
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
class A {
static #P = "PASS";
static get Q() {
return this.#P;
}
#p(n) {
return (this["q"] = n) * this.r;
}
set q(v) {
this.r = v + 1;
}
r = this.#p(6);
}
console.log(A.Q, new A().r);
}
expect: {
class A {
static #t = "PASS";
static get s() {
return this.#t;
}
#i(t) {
return (this["q"] = t) * this.e;
}
set q(t) {
this.e = t + 1;
}
e = this.#i(6);
}
console.log(A.s, new A().e);
}
expect_stdout: "PASS 42"
node_version: ">=14.6"
}
issue_4848: {
options = {
if_return: true,
}
input: {
"use strict";
function f(a) {
a(function() {
new A();
});
if (!console)
return;
class A {
constructor() {
console.log("PASS");
}
}
}
var g;
f(function(h) {
g = h;
});
g();
}
expect: {
"use strict";
function f(a) {
a(function() {
new A();
});
if (!console)
return;
class A {
constructor() {
console.log("PASS");
}
}
}
var g;
f(function(h) {
g = h;
});
g();
}
expect_stdout: "PASS"
node_version: ">=4"
}
drop_unused_self_reference: {
options = {
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
(A.p = A).q = console.log("PASS");
}
expect: {
"use strict";
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4951_1: {
input: {
class A {
static#p = console.log("PASS");
}
}
expect_exact: 'class A{static#p=console.log("PASS")}'
expect_stdout: "PASS"
node_version: ">=12"
}
issue_4951_2: {
input: {
new class {
constructor() {
this.#f().then(console.log);
}
async#f() {
return await "PASS";
}
}();
}
expect_exact: 'new class{constructor(){this.#f().then(console.log)}async#f(){return await"PASS"}};'
expect_stdout: "PASS"
node_version: ">=14.6"
}
issue_4962_1: {
options = {
ie8: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
function f() {
while (console.log(typeof g));
}
class A {
static p = f();
}
})(function g() {});
}
expect: {
(function g() {}),
void function() {
while (console.log(typeof g));
}();
}
expect_stdout: "undefined"
node_version: ">=12"
}
issue_4962_2: {
options = {
ie8: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function f() {}(function g() {
function h() {
f;
}
class A {
static p = h();
}
}, typeof g));
}
expect: {
console.log(function f() {}(function g() {
f;
}));
}
expect_stdout: "undefined"
node_version: ">=12"
}
issue_4982_1: {
options = {
dead_code: true,
}
input: {
"use strict";
try {} catch (e) {
class A extends 42 {}
}
console.log("PASS");
}
expect: {
"use strict";
{
class A {}
}
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4982_2: {
options = {
dead_code: true,
}
input: {
var a = "PASS";
try {} catch (e) {
class A {
static p = a = "FAIL";
}
}
console.log(a);
}
expect: {
var a = "PASS";
{
class A {}
}
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=12"
}
issue_4992: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
class A {
static P = this;
get p() {}
}
console.log(typeof A.P);
}
expect: {
console.log(typeof class {
static P = this;
get p() {}
}.P);
}
expect_stdout: "function"
node_version: ">=12"
}
issue_4996_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
console.log(new class A {
p = a-- && new A();
}().p.p);
}
expect: {
var a = 1;
console.log(new class A {
p = a-- && new A();
}().p.p);
}
expect_stdout: "0"
node_version: ">=12"
}
issue_4996_2: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
console.log(new class A {
p = a-- && new A();
}().p.p);
}
expect: {
var a = 1;
console.log(new class A {
p = a-- && new A();
}().p.p);
}
expect_stdout: "0"
node_version: ">=12"
}
issue_5015_1: {
options = {
side_effects: true,
}
input: {
"use strict";
var a;
try {
(class a {
[a]() {}
});
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
var a;
try {
(class a {
[a]() {}
});
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5015_2: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
"use strict";
try {
new class A {
[(A, 42)]() {}
}();
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
try {
new class A {
[(A, 42)]() {}
}();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5015_3: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
"use strict";
(class A {
static f() {
return A;
}
});
console.log("PASS");
}
expect: {
"use strict";
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -2264,6 +2264,7 @@ var_defs: {
properties: true, properties: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {
@@ -2486,6 +2487,7 @@ issue_1858: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: true, pure_getters: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -2907,6 +2909,7 @@ compound_assignment_2: {
issue_2187_1: { issue_2187_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -4271,6 +4274,7 @@ issue_2436_14: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true, reduce_vars: true,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {
@@ -4761,6 +4765,7 @@ unsafe_builtin: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: "strict", pure_getters: "strict",
reduce_vars: true,
unsafe: true, unsafe: true,
unused: true, unused: true,
} }
@@ -6965,6 +6970,7 @@ sequence_in_iife_2: {
inline: true, inline: true,
passes: 2, passes: 2,
side_effects: true, side_effects: true,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {
@@ -6976,7 +6982,7 @@ sequence_in_iife_2: {
} }
expect: { expect: {
var a = "foo", b = 42; var a = "foo", b = 42;
console.log(a, b = a); console.log(b = a, b);
} }
expect_stdout: "foo foo" expect_stdout: "foo foo"
} }
@@ -6988,6 +6994,7 @@ sequence_in_iife_3: {
passes: 2, passes: 2,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
unsafe: true,
unused: true, unused: true,
} }
input: { input: {
@@ -7092,6 +7099,7 @@ setter_side_effect: {
substitution_assign: { substitution_assign: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unsafe: true,
} }
input: { input: {
function f1(a, b) { function f1(a, b) {
@@ -7112,8 +7120,7 @@ substitution_assign: {
} }
expect: { expect: {
function f1(a, b) { function f1(a, b) {
f1 = a; console.log(f1 = a, a);
console.log(a, a);
} }
function f2(a, b) { function f2(a, b) {
a = 1 + (b = a); a = 1 + (b = a);
@@ -7917,6 +7924,7 @@ issue_3744: {
assign_value_def: { assign_value_def: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -7957,6 +7965,7 @@ join_vars_value_def: {
options = { options = {
collapse_vars: true, collapse_vars: true,
join_vars: true, join_vars: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -7996,6 +8005,7 @@ join_vars_value_def: {
var_value_def: { var_value_def: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -8033,6 +8043,7 @@ var_value_def: {
mangleable_var: { mangleable_var: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -8064,6 +8075,69 @@ mangleable_var: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
mangleable_assignment_1: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var o = {
p: function() {
return 6;
},
};
(function() {
var a, b = a = o.p();
console.log(a * (b / a + b));
})();
}
expect: {
var o = {
p: function() {
return 6;
},
};
(function() {
var a;
a = o.p();
console.log(a * (a / a + a));
})();
}
expect_stdout: "42"
}
mangleable_assignment_2: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var o = {
p: function() {
return 6;
},
};
(function(a, b) {
b = a = o.p();
console.log(a * (b / a + b));
})();
}
expect: {
var o = {
p: function() {
return 6;
},
};
(function(a, b) {
a = o.p();
console.log(a * (a / a + a));
})();
}
expect_stdout: "42"
}
issue_3884_1: { issue_3884_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -8499,7 +8573,7 @@ issue_4047_1: {
expect: { expect: {
var b = 1; var b = 1;
var a; var a;
console.log((a = --b + ((a = 0) !== typeof A), +void ((a >>= 0) && console.log("PASS")))); console.log((a = --b + (0 !== typeof A), +void ((a >>= 0) && console.log("PASS"))));
} }
expect_stdout: [ expect_stdout: [
"PASS", "PASS",
@@ -8789,7 +8863,7 @@ issue_4732_1: {
expect: { expect: {
var a = 0; var a = 0;
(function(b) { (function(b) {
(b = a++) && (b && console.log("PASS")); (b = a++) && console.log("PASS");
})(a++); })(a++);
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@@ -8878,6 +8952,8 @@ dot_non_local: {
issue_4806: { issue_4806: {
options = { options = {
collapse_vars: true, collapse_vars: true,
reduce_vars: true,
toplevel: true,
} }
input: { input: {
var a, o = { var a, o = {
@@ -8897,3 +8973,442 @@ issue_4806: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_4852: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
var a = "PASS";
(function(b) {
switch (b = a) {
case 42:
try {
console;
} catch (b) {
b.p;
}
case console.log(b):
}
})("FAIL");
}
expect: {
var a = "PASS";
(function(b) {
switch (a) {
case 42:
try {
console;
} catch (b) {
b.p;
}
case console.log(a):
}
})("FAIL");
}
expect_stdout: "PASS"
}
issue_4865: {
options = {
collapse_vars: true,
}
input: {
var NaN;
var a = NaN = "PASS";
console.log(a, NaN);
}
expect: {
var NaN;
var a = NaN = "PASS";
console.log(a, NaN);
}
expect_stdout: true
}
issue_4868: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a;
(function(b) {
console.log(b[0]);
})(a = [ "PASS" ], a = [ "FAIL" ]);
}
expect: {
var a;
(function(b) {
console.log(b[0]);
})(a = [ "PASS" ], a = [ "FAIL" ]);
}
expect_stdout: "PASS"
}
issue_4874: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
a = null;
(function(b) {
for (var c in b = b && b[console.log("PASS")])
console;
})(a = 42);
}
expect: {
var a;
null;
(function(b) {
for (var c in a && a[console.log("PASS")])
console;
})(a = 42);
}
expect_stdout: "PASS"
}
issue_4891: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0, b;
a++;
console.log(b = a, b);
b--;
a.a += 0;
console.log(b);
}
expect: {
var a = 0, b;
a++;
console.log(a, b = a);
b--;
a.a += 0;
console.log(b);
}
expect_stdout: [
"1 1",
"0",
]
}
issue_4895: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var a, b;
(function f() {
a = 42;
})();
console.log((b = a) || b, b += 0);
}
expect: {
var a, b;
(function f() {
a = 42;
})();
console.log((b = a) || b, b += 0);
}
expect_stdout: "42 42"
}
issue_4908: {
options = {
collapse_vars: true,
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0;
var b;
console || a++;
var c = d = a, d = [ c && c, d += 42 ];
console.log(d[1]);
}
expect: {
var a = 0, b;
console || a++;
var c = a, d = [ (d = a) && d, d += 42 ];
console.log(d[1]);
}
expect_stdout: "42"
}
issue_4910: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = "foo", b;
var c = b = a;
1 && c[a = "bar"];
console.log(a, b);
}
expect: {
var a = "foo", b;
var c = b = a;
1 && b[a = "bar"];
console.log(a, b);
}
expect_stdout: "bar foo"
}
issue_4914: {
options = {
collapse_vars: true,
pure_getters: "strict",
}
input: {
console.log(typeof function f() {
f.__proto__ = 42;
return f.__proto__;
}());
}
expect: {
console.log(typeof function f() {
f.__proto__ = 42;
return f.__proto__;
}());
}
expect_stdout: "function"
}
issue_4918: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
({
get 42() {
console.log(a);
}
}[a = "PASS", 42] += "PASS");
}
expect: {
var a = "FAIL";
({
get 42() {
console.log(a);
}
}[a = "PASS", 42] += "PASS");
}
expect_stdout: "PASS"
}
issue_4920_1: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var a = "PASS", b;
({
get PASS() {
a = "FAIL";
},
})[b = a];
console.log(b);
}
expect: {
var a = "PASS", b;
({
get PASS() {
a = "FAIL";
},
})[b = a];
console.log(b);
}
expect_stdout: "PASS"
}
issue_4920_2: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var o = {
get PASS() {
a = "FAIL";
},
};
var a = "PASS", b;
o[b = a];
console.log(b);
}
expect: {
var o = {
get PASS() {
a = "FAIL";
},
};
var a = "PASS", b;
o[b = a];
console.log(b);
}
expect_stdout: "PASS"
}
issue_4920_3: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var o = {
get PASS() {
a = "FAIL";
},
};
var a = "PASS", b;
o[b = a];
log(b);
}
expect: {
var log = console.log;
var o = {
get PASS() {
a = "FAIL";
},
};
var a = "PASS", b;
o[b = a];
log(b);
}
expect_stdout: "PASS"
}
issue_4935: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
var b;
var c = b = a;
console || c(a++);
--b;
console.log(a, b);
}
expect: {
var a = 1;
var b;
var c = b = a;
console || a(a++);
--b;
console.log(a, b);
}
expect_stdout: "1 0"
}
inline_throw: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: false,
unused: true,
}
input: {
try {
(function() {
return function(a) {
return function(b) {
throw b;
}(a);
};
})()("PASS");
} catch (e) {
console.log(e);
}
}
expect: {
try {
(function(a) {
return function() {
throw a;
}();
})("PASS");
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
}
issue_4977_1: {
options = {
collapse_vars: true,
unsafe: true,
}
input: {
var a = "FAIL";
var o = {
get p() {
return a;
}
};
a = "PASS";
console.log(o.p, a);
}
expect: {
var a = "FAIL";
var o = {
get p() {
return a;
}
};
a = "PASS";
console.log(o.p, a);
}
expect_stdout: "PASS PASS"
}
issue_4977_2: {
options = {
collapse_vars: true,
reduce_vars: true,
unsafe: true,
}
input: {
var a, o = {
get p() {
return a = "PASS";
},
};
if (console) {
var a = "FAIL";
console.log(o.p, a);
}
}
expect: {
var a, o = {
get p() {
return a = "PASS";
},
};
if (console) {
var a = "FAIL";
console.log(o.p, a);
}
}
expect_stdout: "PASS PASS"
}

View File

@@ -822,6 +822,33 @@ cond_13: {
} }
} }
cond_14: {
options = {
booleans: true,
conditionals: true,
side_effects: true,
}
input: {
function f(a) {
if (a)
if (a)
console.log("PASS");
else
console.log("FAIL");
}
f(null);
f(42);
}
expect: {
function f(a) {
a && console.log("PASS");
}
f(null);
f(42);
}
expect_stdout: "PASS"
}
ternary_boolean_consequent: { ternary_boolean_consequent: {
options = { options = {
booleans: true, booleans: true,

View File

@@ -1498,3 +1498,197 @@ issue_4691: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_4848: {
options = {
if_return: true,
}
input: {
function f(a) {
a(function() {
console.log(b);
});
if (!console)
return;
const b = "PASS";
}
var g;
f(function(h) {
g = h;
});
g();
}
expect: {
function f(a) {
a(function() {
console.log(b);
});
if (!console)
return;
const b = "PASS";
}
var g;
f(function(h) {
g = h;
});
g();
}
expect_stdout: "PASS"
}
issue_4954_1: {
rename = true
input: {
"use strict";
(function() {
{
const a = "foo";
console.log(a);
}
{
const a = "bar";
console.log(a);
}
})();
}
expect: {
"use strict";
(function() {
{
const a = "foo";
console.log(a);
}
{
const b = "bar";
console.log(b);
}
})();
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=4"
}
issue_4954_2: {
mangle = {}
input: {
"use strict";
const a = null;
(function(b) {
for (const a in null);
for (const a in b)
console.log("PASS");
})([ null ]);
}
expect: {
"use strict";
const a = null;
(function(o) {
for (const n in null);
for (const n in o)
console.log("PASS");
})([ null ]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4960: {
mangle = {}
input: {
"use strict";
var a;
(function() {
{
const a = console.log("PASS");
}
try {} catch (e) {
const a = console.log("FAIL");
}
})();
}
expect: {
"use strict";
var a;
(function() {
{
const o = console.log("PASS");
}
try {} catch (o) {
const c = console.log("FAIL");
}
})();
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4965_1: {
mangle = {}
input: {
"use strict";
try {
c;
} catch (a) {
{
const a = 1;
}
{
const a = console.log(typeof c);
}
}
}
expect: {
"use strict";
try {
c;
} catch (t) {
{
const c = 1;
}
{
const t = console.log(typeof c);
}
}
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_4965_2: {
mangle = {}
input: {
"use strict";
try {
throw 1;
} catch (e) {
try {
{
const e = 2;
}
} finally {
const e = 3;
console.log(typeof t);
}
}
}
expect: {
"use strict";
try {
throw 1;
} catch (o) {
try {
{
const t = 2;
}
} finally {
const o = 3;
console.log(typeof t);
}
}
}
expect_stdout: "undefined"
node_version: ">=4"
}

View File

@@ -939,6 +939,185 @@ catch_return_assign: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
catch_return_assign_may_throw: {
options = {
dead_code: true,
}
input: {
function f() {
try {
throw "FAIL";
} catch (e) {
return e = console.log("PASS");
}
}
f();
}
expect: {
function f() {
try {
throw "FAIL";
} catch (e) {
return console.log("PASS");
}
}
f();
}
expect_stdout: "PASS"
}
finally_return_assign: {
options = {
dead_code: true,
}
input: {
console.log(function(a) {
try {
throw "FAIL";
} finally {
return a = "PASS";
}
}());
}
expect: {
console.log(function(a) {
try {
throw "FAIL";
} finally {
return "PASS";
}
}());
}
expect_stdout: "PASS"
}
last_assign_statement: {
options = {
dead_code: true,
}
input: {
function f(a) {
a = a("PASS");
}
f(console.log);
}
expect: {
function f(a) {
a("PASS");
}
f(console.log);
}
expect_stdout: "PASS"
}
last_assign_if_else: {
options = {
dead_code: true,
}
input: {
function f(a) {
if (a)
a = console.log("foo");
else {
console.log("bar");
a = 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",
"bar",
"baz",
]
}
last_assign_catch: {
options = {
dead_code: true,
}
input: {
function f() {
try {
throw "FAIL";
} catch (e) {
e = console.log("PASS");
}
}
f();
}
expect: {
function f() {
try {
throw "FAIL";
} catch (e) {
console.log("PASS");
}
}
f();
}
expect_stdout: "PASS"
}
last_assign_finally: {
options = {
dead_code: true,
}
input: {
function f(a) {
try {
throw a.log;
} catch (e) {
a = e;
} finally {
a = a("PASS");
}
}
f(console);
}
expect: {
function f(a) {
try {
throw a.log;
} catch (e) {
a = e;
} finally {
a("PASS");
}
}
f(console);
}
expect_stdout: "PASS"
}
consecutive_assignments: {
options = {
dead_code: true,
}
input: {
while (a = void 0, a = "PASS", console.log(a));
var a;
}
expect: {
while (void 0, a = "PASS", console.log(a));
var a;
}
expect_stdout: "PASS"
}
issue_3578: { issue_3578: {
options = { options = {
dead_code: true, dead_code: true,
@@ -1420,3 +1599,37 @@ issue_4570: {
} }
expect_stdout: "NaN" expect_stdout: "NaN"
} }
issue_5030: {
options = {
dead_code: true,
}
input: {
(function(a, b) {
a = function f() {
if (a)
if (b--)
setImmediate(f);
else
console.log("FAIL");
else
console.log("PASS");
}();
})(42, 1);
}
expect: {
(function(a, b) {
a = function f() {
if (a)
if (b--)
setImmediate(f);
else
console.log("FAIL");
else
console.log("PASS");
}();
})(42, 1);
}
expect_stdout: "PASS"
node_version: ">=0.12"
}

View File

@@ -422,7 +422,9 @@ inline_loop_1: {
inline_loop_2: { inline_loop_2: {
options = { options = {
inline: true, inline: true,
sequences: true,
toplevel: true, toplevel: true,
unused: true,
} }
input: { input: {
while (function(a = [ "PASS" ]) { while (function(a = [ "PASS" ]) {
@@ -432,10 +434,11 @@ inline_loop_2: {
}()); }());
} }
expect: { expect: {
while (a = [ "PASS" ], a = function f(b) { while (a = [ "PASS" ],
console.log(a[b]); b = void 0,
}(0), void 0) ; b = 0,
var a; void (a = void console.log(a[b])));
var a, b;
} }
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
@@ -598,6 +601,7 @@ unused_var_1: {
unused_var_2: { unused_var_2: {
options = { options = {
pure_getters: "strict",
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -609,11 +613,7 @@ unused_var_2: {
}; };
} }
expect: { expect: {
var { console.log("PASS");
p: [] = [ console.log("FAIL") ],
} = {
p: [ console.log("PASS") ],
};
} }
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
@@ -1681,3 +1681,76 @@ issue_4817: {
expect_stdout: "function" expect_stdout: "function"
node_version: ">=6" node_version: ">=6"
} }
issue_4854: {
options = {
collapse_vars: true,
inline: true,
side_effects: true,
unused: true,
}
input: {
console.log(function(a) {
(function(b = a = "foo") {
[] = "foo";
})();
a;
}());
}
expect: {
console.log(void ([] = "foo"));
}
expect_stdout: "undefined"
node_version: ">=6"
}
issue_4916: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
}
input: {
var log = console.log;
(function(b = "foo") {
b.value = "FAIL";
b;
log(b.value);
})();
}
expect: {
var log = console.log;
(function(b = "foo") {
b.value = "FAIL";
b;
log(b.value);
})();
}
expect_stdout: "undefined"
node_version: ">=6"
}
issue_4994: {
options = {
loops: true,
unused: true,
}
input: {
var a = "FAIL";
(function(b = function() {
for (a in { PASS: 42 });
}()) {
var a;
})();
console.log(a);
}
expect: {
var a = "FAIL";
(function(b = function() {
for (a in { PASS: 42 });
}()) {})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -1010,6 +1010,42 @@ collapse_vars_8: {
node_version: ">=6" node_version: ">=6"
} }
collapse_vars_9: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
try {
var b = function([ c ]) {
if (c)
return "FAIL 1";
}();
a = "FAIL 2";
return b;
} catch (e) {
return a;
}
}("PASS"));
}
expect: {
console.log(function(a) {
try {
var b = function([ c ]) {
if (c)
return "FAIL 1";
}();
a = "FAIL 2";
return b;
} catch (e) {
return a;
}
}("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
conditionals: { conditionals: {
options = { options = {
conditionals: true, conditionals: true,
@@ -2556,3 +2592,58 @@ issue_4608_2: {
expect_stdout: "f" expect_stdout: "f"
node_version: ">=6" node_version: ">=6"
} }
issue_4994: {
options = {
loops: true,
unused: true,
}
input: {
var a = "FAIL";
(function([
{
[function() {
for (a in { PASS: null });
}()]: b,
},
]) {
var a;
})([ 42 ]);
console.log(a);
}
expect: {
var a = "FAIL";
(function([
{
[function() {
for (a in { PASS: null });
}()]: b,
},
]) {})([ 42 ]);
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5017: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = function() {};
var b = c = a;
var c = [ c ] = [ c ];
console.log(c[0] === a ? "PASS" : "FAIL");
}
expect: {
var a = function() {};
var b = a;
var c = [ c ] = [ c = a ];
console.log(c[0] === a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -2371,6 +2371,7 @@ function_parameter_ie8: {
issue_3664: { issue_3664: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
side_effects: true,
unused: true, unused: true,
} }
input: { input: {
@@ -2381,7 +2382,7 @@ issue_3664: {
} }
expect: { expect: {
console.log(function() { console.log(function() {
var b = ([ b && console.log("FAIL") ].p = 0, 0); var a, b = (a = (a = [ b && console.log("FAIL") ]).p = 0, 0);
return "PASS"; return "PASS";
}()); }());
} }
@@ -2391,6 +2392,7 @@ issue_3664: {
issue_3673: { issue_3673: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
sequences: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -2401,8 +2403,6 @@ issue_3673: {
console.log("PASS"); console.log("PASS");
} }
expect: { expect: {
var a;
(a = [ a ]).p = 42;
console.log("PASS"); console.log("PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@@ -3080,11 +3080,9 @@ issue_4235: {
})(); })();
} }
expect: { expect: {
(function() { void function() {
f = console.log(f), var f = console.log(f);
void 0; }();
var f;
})();
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
@@ -3357,3 +3355,116 @@ issue_4806_3: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_4834: {
options = {
inline: true,
keep_fargs: false,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
try {
new function(a, b) {
b;
b.p;
}(42);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
void b.p;
} catch (e) {
console.log("PASS");
}
var b;
}
expect_stdout: "PASS"
}
issue_4912_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = A = function() {};
A;
a.prototype = {
f: function() {
console.log("PASS");
},
};
new A().f();
}
expect: {
var a = A = function() {};
A;
a.prototype = {
f: function() {
console.log("PASS");
},
};
new A().f();
}
expect_stdout: "PASS"
}
issue_4912_2: {
options = {
pure_getters: "strict",
unused: true,
}
input: {
console.log(function() {
var g, f = function() {};
f.p = {};
(g = f.p.q = function() {}).r = "PASS";
return f;
}().p.q.r);
}
expect: {
console.log(function() {
var g, f = function() {};
f.p = {};
(f.p.q = function() {}).r = "PASS";
return f;
}().p.q.r);
}
expect_stdout: "PASS"
}
issue_4912_3: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function(f, g) {
f = function() {};
f.p = {};
g = f.p.q = function() {};
g.r = "PASS";
return f;
}().p.q.r);
}
expect: {
console.log(function(f, g) {
f = function() {};
f.p = {};
g = f.p.q = function() {};
g.r = "PASS";
return f;
}().p.q.r);
}
expect_stdout: "PASS"
}

View File

@@ -3181,3 +3181,23 @@ issue_4552: {
} }
expect_stdout: "NaN" expect_stdout: "NaN"
} }
issue_4886: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log("length" in {
__proto__: function() {},
length: void 0,
});
}
expect: {
console.log("length" in {
__proto__: function() {},
length: void 0,
});
}
expect_stdout: "true"
}

View File

@@ -99,8 +99,8 @@ issue_4664: {
expect: { expect: {
(function f() { (function f() {
new function(a) { new function(a) {
console.log(typeof f, 2 ** 30, typeof this); console.log(typeof f, 1073741824, typeof this);
}(0, A = 0); }(A = 0);
})(); })();
} }
expect_stdout: "function 1073741824 object" expect_stdout: "function 1073741824 object"

View File

@@ -91,6 +91,13 @@ defaults_parentheses_6: {
expect_exact: 'export default(function(){while(!console);})()?"FAIL":"PASS";' expect_exact: 'export default(function(){while(!console);})()?"FAIL":"PASS";'
} }
defaults_regexp: {
input: {
export default /foo/;
}
expect_exact: "export default/foo/;"
}
foreign: { foreign: {
input: { input: {
export * from "foo"; export * from "foo";

View File

@@ -5236,7 +5236,7 @@ issue_4265: {
expect: { expect: {
function f() { function f() {
return console, function() { return console, function() {
return console.log(a); console.log(a);
var a; var a;
}(), 0; }(), 0;
} }
@@ -6013,7 +6013,7 @@ issue_4823: {
console.log(typeof function() { console.log(typeof function() {
{ {
function f() {} function f() {}
arguments = f(); f();
var arguments = function() {}; var arguments = function() {};
} }
return f && arguments; return f && arguments;
@@ -6021,3 +6021,265 @@ issue_4823: {
} }
expect_stdout: "function" expect_stdout: "function"
} }
drop_unused_self_reference: {
options = {
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {}
(f.p = f).q = console.log("PASS");
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
reduce_cross_reference_1: {
options = {
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(a, b) {
a = b = function() {};
a.p = a;
b = a = function() {};
b.q = b;
})();
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_1_toplevel: {
options = {
passes: 2,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = b = function() {};
a.p = a;
var b = a = function() {};
b.q = b;
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_2: {
options = {
collapse_vars: true,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(a, b) {
a = b = function() {};
b.p = a;
b = a = function() {};
a.q = b;
})();
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_2_toplevel: {
options = {
collapse_vars: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = b = function() {};
b.p = a;
var b = a = function() {};
a.q = b;
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_3: {
options = {
collapse_vars: true,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(a, b) {
a = b = function() {};
a.p = b;
b = a = function() {};
b.q = a;
})();
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_3_toplevel: {
options = {
collapse_vars: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = b = function() {};
a.p = b;
var b = a = function() {};
b.q = a;
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_4: {
options = {
passes: 3,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(a, b) {
a = b = function() {};
b.p = b;
b = a = function() {};
a.q = a;
})();
}
expect: {}
expect_stdout: true
}
reduce_cross_reference_4_toplevel: {
options = {
passes: 2,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = b = function() {};
b.p = b;
var b = a = function() {};
a.q = a;
}
expect: {}
expect_stdout: true
}
recursive_collapse: {
options = {
collapse_vars: true,
reduce_vars: true,
}
input: {
console.log(function f(a) {
var b = a && f();
return b;
}("FAIL") || "PASS");
}
expect: {
console.log(function f(a) {
var b;
return a && f();
}("FAIL") || "PASS");
}
expect_stdout: "PASS"
}
issue_5025: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
function g() {
b = 42;
}
g(b = a);
var b = this;
console.log(typeof b);
}
f();
}
expect: {
function f(a) {
b = a,
void (b = 42);
var b = this;
console.log(typeof b);
}
f();
}
expect_stdout: "object"
}
issue_5036: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(typeof function() {
var await = function f() {
return f;
};
return await() === await;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(typeof function() {
function await() {
return await;
}
return await() === await;
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}

View File

@@ -140,7 +140,6 @@ issue_4487: {
functions: true, functions: true,
hoist_vars: true, hoist_vars: true,
keep_fnames: true, keep_fnames: true,
passes: 2,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -240,3 +239,160 @@ issue_4736: {
} }
expect_stdout: "1073741824" expect_stdout: "1073741824"
} }
issue_4839: {
options = {
evaluate: true,
hoist_vars: true,
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = function(a, b) {
return b && b;
}("foo");
for (var k in o)
throw "FAIL";
console.log("PASS");
}
expect: {
var k, o = void 0;
for (k in o)
throw "FAIL";
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4859: {
options = {
evaluate: true,
hoist_vars: true,
keep_infinity: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a) {
var b = (a = 2, 1 / 0), c = 3;
var d = a + b;
console.log(d);
return f;
}
f();
}
expect: {
(function f(a) {
var d = 1 / 0, d = Infinity;
console.log(d);
return f;
})();
}
expect_stdout: "Infinity"
}
issue_4893_1: {
options = {
collapse_vars: true,
evaluate: true,
hoist_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {}
var a = null;
var b = null;
var c = null;
b.p += a = 42;
f;
}
try {
f();
} catch (e) {
console.log("PASS");
}
}
expect: {
try{
(function f() {
var b;
b = null;
b.p += 42;
f;
})();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4893_2: {
options = {
collapse_vars: true,
hoist_vars: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {}
var a = null;
var b = null;
var c = null;
b.p += a = 42;
f;
}
try {
f();
} catch (e) {
console.log("PASS");
}
}
expect: {
try{
(function() {
var b;
b = null;
b.p += 42;
})();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4898: {
options = {
collapse_vars: true,
evaluate: true,
hoist_vars: true,
loops: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
do {
var b = [ console.log("PASS") ];
var c = b;
} while (c.p = 0);
}
expect: {
var b;
b = [ console.log("PASS") ];
b.p = 0;
}
expect_stdout: "PASS"
}

View File

@@ -2653,7 +2653,9 @@ issue_4019: {
try { try {
console.log("FAIL"); console.log("FAIL");
} catch (o) {} } catch (o) {}
}, o = (console.log(o.length), ++o); };
console.log(o.length),
++o;
} }
expect_stdout: "0" expect_stdout: "0"
} }
@@ -2945,3 +2947,73 @@ issue_4729: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_4928_1: {
options = {
ie8: true,
toplevel: true,
unused: true,
}
input: {
var a = function f() {
f(a);
};
console.log(typeof f);
}
expect: {
var a = function f() {
f(a);
};
console.log(typeof f);
}
expect_stdout: "undefined"
}
issue_4928_2: {
options = {
ie8: true,
toplevel: true,
unused: true,
}
input: {
switch (42) {
case console:
var a = function f() {
f(a);
};
case 42:
var a = console.log("PASS");
}
}
expect: {
switch (42) {
case console:
var a = function f() {
f(a);
};
case 42:
a = console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4958: {
options = {
collapse_vars: true,
ie8: true,
}
input: {
console.log(function arguments(a) {
a = 21;
return arguments[0] + 21;
}("FAIL"));
}
expect: {
console.log(function arguments(a) {
a = 21;
return arguments[0] + 21;
}("FAIL"));
}
expect_stdout: "42"
}

View File

@@ -54,13 +54,22 @@ dynamic_nought: {
expect_exact: "import(foo);" expect_exact: "import(foo);"
} }
import_meta: { import_meta_1: {
input: { input: {
console.log(import.meta, import.meta.url); console.log(import.meta, import.meta.url);
} }
expect_exact: "console.log(import.meta,import.meta.url);" expect_exact: "console.log(import.meta,import.meta.url);"
} }
import_meta_2: {
input: {
import.meta.url.split("/").forEach(function(part, index) {
console.log(index, part);
});
}
expect_exact: 'import.meta.url.split("/").forEach(function(part,index){console.log(index,part)});'
}
same_quotes: { same_quotes: {
beautify = { beautify = {
beautify: true, beautify: true,
@@ -85,13 +94,15 @@ drop_unused: {
} }
input: { input: {
import a, * as b from "foo"; import a, * as b from "foo";
import { c, bar as d } from "baz"; import { c } from "bar";
console.log(c); import { d, _ as e } from "baz";
console.log(d);
} }
expect: { expect: {
import "foo"; import "foo";
import { c as c } from "baz"; import "bar";
console.log(c); import { d as d } from "baz";
console.log(d);
} }
} }

View File

@@ -1015,7 +1015,7 @@ issue_3856: {
console.log(function() { console.log(function() {
(function() { (function() {
var a, b; var a, b;
if (a) return !!a; if (a) return a, 1;
for (a = 0; !console;); for (a = 0; !console;);
return 0; return 0;
})(); })();
@@ -1024,7 +1024,7 @@ issue_3856: {
expect_stdout: "undefined" expect_stdout: "undefined"
} }
issue_3916: { issue_3916_1: {
options = { options = {
join_vars: true, join_vars: true,
} }
@@ -1044,8 +1044,8 @@ issue_3916: {
var o = { var o = {
p: "PASS", p: "PASS",
__proto__: 42, __proto__: 42,
q: "FAIL",
}; };
o.q = "FAIL";
o.__proto__ = { o.__proto__ = {
p: "FAIL", p: "FAIL",
q: "PASS", q: "PASS",
@@ -1056,6 +1056,62 @@ issue_3916: {
expect_stdout: "object PASS true PASS" expect_stdout: "object PASS true PASS"
} }
issue_3916_2: {
options = {
join_vars: true,
}
input: {
var log = console.log, o = {};
o.p = "FAIL 1";
o.__proto__ = {
get p() {
return "FAIL 2";
},
set p(u) {
log("FAIL 3");
},
set q(v) {
log("PASS 1");
},
get q() {
return "PASS 3";
},
};
o.p = "PASS 2";
o.q = "FAIL 4";
log(o.p);
log(o.q);
}
expect: {
var log = console.log, o = {
p: "FAIL 1",
__proto__: {
get p() {
return "FAIL 2";
},
set p(u) {
log("FAIL 3");
},
set q(v) {
log("PASS 1");
},
get q() {
return "PASS 3";
},
},
};
o.p = "PASS 2";
o.q = "FAIL 4";
log(o.p);
log(o.q);
}
expect_stdout: [
"PASS 1",
"PASS 2",
"PASS 3",
]
}
assign_var: { assign_var: {
options = { options = {
join_vars: true, join_vars: true,

View File

@@ -117,6 +117,7 @@ issue_1858: {
collapse_vars: true, collapse_vars: true,
keep_fargs: false, keep_fargs: false,
pure_getters: true, pure_getters: true,
reduce_vars: true,
unused: true, unused: true,
} }
input: { input: {
@@ -1157,8 +1158,8 @@ replace_all_var_scope: {
var a = 100, b = 10; var a = 100, b = 10;
(function(r, a) { (function(r, a) {
switch (~a) { switch (~a) {
case (b += a): case (b += a):
case a++: case a++:
} }
})(--b, a); })(--b, a);
console.log(a, b); console.log(a, b);
@@ -1167,8 +1168,8 @@ replace_all_var_scope: {
var a = 100, b = 10; var a = 100, b = 10;
(function(c) { (function(c) {
switch (~a) { switch (~a) {
case (b += a): case (b += a):
case c++: case c++:
} }
})((--b, a)); })((--b, a));
console.log(a, b); console.log(a, b);

View File

@@ -20,6 +20,39 @@ retain_block: {
node_version: ">=4" node_version: ">=4"
} }
retain_assignment: {
options = {
dead_code: true,
reduce_vars: true,
}
input: {
"use strict";
function f() {
return a = 0;
let a;
}
try {
f();
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
function f() {
return a = 0;
let a;
}
try {
f();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
retain_catch: { retain_catch: {
options = { options = {
dead_code: true, dead_code: true,
@@ -536,6 +569,38 @@ loop_block_2: {
node_version: ">=4" node_version: ">=4"
} }
do_break: {
options = {
loops: true,
}
input: {
"use strict";
try {
do {
if (a)
break;
let a;
} while (!console);
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
try {
do {
if (a)
break;
let a;
} while (!console);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
do_continue: { do_continue: {
options = { options = {
loops: true, loops: true,
@@ -596,6 +661,82 @@ dead_block_after_return: {
node_version: ">=4" node_version: ">=4"
} }
if_return_1: {
options = {
if_return: true,
}
input: {
"use strict";
function f(a) {
function g() {
return b = "PASS";
}
if (a)
return g();
let b;
return g();
};
console.log(f());
}
expect: {
"use strict";
function f(a) {
function g() {
return b = "PASS";
}
if (a)
return g();
let b;
return g();
};
console.log(f());
}
expect_stdout: "PASS"
node_version: ">=4"
}
if_return_2: {
options = {
if_return: true,
}
input: {
"use strict";
function f(a) {
function g() {
return b = "FAIL";
}
if (a)
return g();
let b;
return g();
};
try {
console.log(f(42));
} catch (e) {
console.log("PASS");
}
}
expect: {
"use strict";
function f(a) {
function g() {
return b = "FAIL";
}
if (a)
return g();
let b;
return g();
};
try {
console.log(f(42));
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
do_if_continue_1: { do_if_continue_1: {
options = { options = {
if_return: true, if_return: true,
@@ -897,6 +1038,7 @@ issue_4210: {
issue_4212_1: { issue_4212_1: {
options = { options = {
dead_code: true, dead_code: true,
reduce_vars: true,
} }
input: { input: {
"use strict"; "use strict";
@@ -1506,3 +1648,67 @@ issue_4691: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=4" node_version: ">=4"
} }
issue_4848: {
options = {
if_return: true,
}
input: {
"use strict";
function f(a) {
a(function() {
console.log(b);
});
if (!console)
return;
let b = "PASS";
}
var g;
f(function(h) {
g = h;
});
g();
}
expect: {
"use strict";
function f(a) {
a(function() {
console.log(b);
});
if (!console)
return;
let b = "PASS";
}
var g;
f(function(h) {
g = h;
});
g();
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4985: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
let a = { p: 42 };
console.log(function() {
a;
}());
}
expect: {
"use strict";
let a = { p: 42 };
console.log(function() {
a;
}());
}
expect_stdout: "undefined"
node_version: ">=4"
}

View File

@@ -829,6 +829,18 @@ empty_for_in_prop_init: {
} }
for_of: { for_of: {
input: {
var a = [ "PASS", 42 ];
a.p = "FAIL";
for (a of (null, a))
console.log(a);
}
expect_exact: 'var a=["PASS",42];a.p="FAIL";for(a of(null,a))console.log(a);'
expect_stdout: true
node_version: ">=0.12"
}
for_async_of: {
input: { input: {
var async = [ "PASS", 42 ]; var async = [ "PASS", 42 ];
async.p = "FAIL"; async.p = "FAIL";
@@ -837,7 +849,21 @@ for_of: {
} }
expect_exact: 'var async=["PASS",42];async.p="FAIL";for(async of(null,async))console.log(async);' expect_exact: 'var async=["PASS",42];async.p="FAIL";for(async of(null,async))console.log(async);'
expect_stdout: true expect_stdout: true
node_version: ">=0.12" node_version: ">=0.12 <16"
}
for_of_regexp: {
input: {
for (var a of /foo/);
}
expect_exact: "for(var a of/foo/);"
}
for_await_of_regexp: {
input: {
for await (var a of /foo/);
}
expect_exact: "for await(var a of/foo/);"
} }
issue_3631_1: { issue_3631_1: {

View File

@@ -3075,7 +3075,7 @@ issue_4237_2: {
console.log(function(a) { console.log(function(a) {
do { do {
switch (0) { switch (0) {
case 0: default:
var b = a++; var b = a++;
if (b) if (b)
return "FAIL"; return "FAIL";
@@ -3301,3 +3301,80 @@ issue_4761: {
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
issue_4956_1: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
var a, b;
function f(c) {
switch (c) {
case 0:
a = { p: 42 };
case 1:
b = a.p;
console.log(b);
}
}
f(0);
f(1);
}
expect: {
var a, b;
function f(c) {
switch (c) {
case 0:
a = { p: 42 };
case 1:
b = a.p;
console.log(b);
}
}
f(0);
f(1);
}
expect_stdout: [
"42",
"42",
]
}
issue_4956_2: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
var a, b;
function f(c) {
if (0 == c) {
console;
a = { p: 42 };
}
b = a.p;
if (1 == c)
console.log(b);
}
f(0);
f(1);
}
expect: {
var a, b;
function f(c) {
if (0 == c) {
console;
a = { p: 42 };
}
b = a.p;
if (1 == c)
console.log(b);
}
f(0);
f(1);
}
expect_stdout: "42"
}

View File

@@ -110,6 +110,158 @@ conditional_assignment_4: {
node_version: ">=14" node_version: ">=14"
} }
de_morgan_1: {
options = {
booleans: true,
}
input: {
function f(a) {
return a ?? a;
}
console.log(f(null), f(42));
}
expect: {
function f(a) {
return a;
}
console.log(f(null), f(42));
}
expect_stdout: "null 42"
node_version: ">=14"
}
de_morgan_2a: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
}
input: {
function f(a, b) {
return a || (a ?? b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a || (a ?? b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"undefined {}",
"42 42",
]
node_version: ">=14"
}
de_morgan_2b: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b) {
return a && (a ?? b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"42 42",
]
node_version: ">=14"
}
de_morgan_2c: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
function f(a, b) {
return a ?? (a || 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: [
"undefined {}",
"42 42",
]
node_version: ">=14"
}
de_morgan_2d: {
options = {
booleans: true,
evaluate: true,
}
input: {
function f(a, b) {
return a ?? (a && b);
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"42 42",
]
node_version: ">=14"
}
de_morgan_2e: {
options = {
booleans: true,
conditionals: true,
}
input: {
function f(a, b) {
return a ?? (a ?? 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: [
"undefined {}",
"42 42",
]
node_version: ">=14"
}
issue_4679: { issue_4679: {
options = { options = {
comparisons: true, comparisons: true,

View File

@@ -104,6 +104,40 @@ parentheses_for_prototype_functions_galio: {
expect_stdout: true expect_stdout: true
} }
octal: {
beautify = {
beautify: true,
}
input: {
(function() {
console.log(052);
console.log(-052);
console.log(018);
console.log(-018);
console.log(052.toFixed(0));
console.log(-052.toFixed(0));
console.log(018..toFixed(0));
console.log(-018..toFixed(0));
})();
}
expect_exact: [
"(function() {",
" console.log(42);",
" console.log(-42);",
" console.log(18);",
" console.log(-18);",
" console.log(42..toFixed(0));",
" console.log(-42..toFixed(0));",
" console.log(18..toFixed(0));",
" console.log(-18..toFixed(0));",
"})();",
]
expect_stdout: true
}
comparisons: { comparisons: {
options = { options = {
comparisons: true, comparisons: true,

View File

@@ -0,0 +1,307 @@
call: {
input: {
console.log?.(undefined?.(console.log("FAIL")));
}
expect_exact: 'console.log?.((void 0)?.(console.log("FAIL")));'
expect_stdout: "undefined"
node_version: ">=14"
}
dot: {
input: {
console?.log((void 0)?.p);
}
expect_exact: "console?.log((void 0)?.p);"
expect_stdout: "undefined"
node_version: ">=14"
}
dot_in: {
input: {
var o = { in: 42 };
console.log(o.in, o?.in);
}
expect_exact: "var o={in:42};console.log(o.in,o?.in);"
expect_stdout: "42 42"
node_version: ">=14"
}
sub: {
input: {
console?.["log"](null?.[console.log("FAIL")]);
}
expect_exact: 'console?.["log"](null?.[console.log("FAIL")]);'
expect_stdout: "undefined"
node_version: ">=14"
}
ternary_decimal: {
input: {
null ? .42 : console.log("PASS");
}
expect_exact: 'null?.42:console.log("PASS");'
expect_stdout: "PASS"
}
assign_parentheses_call: {
input: {
var o = {};
((() => o)?.()).p = "PASS";
console.log(o.p);
}
expect_exact: 'var o={};((()=>o)?.()).p="PASS";console.log(o.p);'
expect_stdout: "PASS"
node_version: ">=14"
}
assign_parentheses_dot: {
input: {
(console?.log).name.p = console.log("PASS");
}
expect_exact: '(console?.log.name).p=console.log("PASS");'
expect_stdout: "PASS"
node_version: ">=14"
}
assign_no_parentheses: {
input: {
console[console.log?.("PASS")] = 42;
}
expect_exact: 'console[console.log?.("PASS")]=42;'
expect_stdout: "PASS"
node_version: ">=14"
}
unary_parentheses: {
input: {
var o = { p: 41 };
(function() {
return o;
}?.()).p++;
console.log(o.p);
}
expect_exact: "var o={p:41};(function(){return o}?.()).p++;console.log(o.p);"
expect_stdout: "42"
node_version: ">=14"
}
collapse_vars_1: {
options = {
collapse_vars: true,
}
input: {
var a;
A = 42;
a?.[42];
console.log(typeof A);
}
expect: {
var a;
A = 42;
a?.[42];
console.log(typeof A);
}
expect_stdout: "number"
node_version: ">=14"
}
collapse_vars_2: {
options = {
collapse_vars: true,
}
input: {
var a;
A = 42;
a?.(42);
console.log(typeof A);
}
expect: {
var a;
A = 42;
a?.(42);
console.log(typeof A);
}
expect_stdout: "number"
node_version: ">=14"
}
properties: {
options = {
evaluate: true,
properties: true,
}
input: {
var a;
console.log(a?.["FAIL"]);
}
expect: {
var a;
console.log(a?.FAIL);
}
expect_stdout: "undefined"
node_version: ">=14"
}
reduce_vars_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
null?.[a = 0];
console.log(a ? "PASS" : "FAIL");
}
expect: {
var a = 1;
null?.[a = 0];
console.log(a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=14"
}
reduce_vars_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
null?.(a = 0);
console.log(a ? "PASS" : "FAIL");
}
expect: {
var a = 1;
null?.(a = 0);
console.log(a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=14"
}
side_effects: {
options = {
side_effects: true,
}
input: {
var a;
a?.[a = "FAIL"];
console.log(a);
}
expect: {
var a;
a?.[a = "FAIL"];
console.log(a);
}
expect_stdout: "undefined"
node_version: ">=14"
}
trim_1: {
options = {
evaluate: true,
optional_chains: true,
reduce_vars: true,
unsafe: true,
}
input: {
(function(a, b) {
console?.log?.(a?.p, b?.[console.log("FAIL")]);
})?.({ p: "PASS" });
}
expect: {
(function(a, b) {
console?.log?.(a.p, void 0);
})({ p: "PASS" });
}
expect_stdout: "PASS undefined"
node_version: ">=14"
}
trim_2: {
options = {
evaluate: true,
optional_chains: true,
side_effects: true,
}
input: {
(void console.log("PASS"))?.[console.log("FAIL")];
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=14"
}
issue_4906: {
options = {
toplevel: true,
unused: true,
}
input: {
do {
var a = a?.[42];
} while (console.log("PASS"));
}
expect: {
do {} while (console.log("PASS"));
}
expect_stdout: "PASS"
node_version: ">=14"
}
issue_4928: {
options = {
ie8: true,
toplevel: true,
unused: true,
}
input: {
var a = a?.[function f() {
f(a);
}];
console.log(typeof f);
}
expect: {
var a = a?.[function f() {
f(a);
}];
console.log(typeof f);
}
expect_stdout: "undefined"
node_version: ">=14"
}
issue_4947_1: {
options = {
conditionals: true,
}
input: {
console.log(console.foo ? 42..p : console.bar?.p);
}
expect: {
console.log(console.foo ? 42..p : console.bar?.p);
}
expect_stdout: "undefined"
node_version: ">=14"
}
issue_4947_2: {
options = {
conditionals: true,
}
input: {
var log = console.log, fail;
log("PASS") ? log(42) : fail?.(42);
}
expect: {
var log = console.log, fail;
log("PASS") ? log(42) : fail?.(42);
}
expect_stdout: "PASS"
node_version: ">=14"
}

View File

@@ -1400,3 +1400,66 @@ object_super: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=4" node_version: ">=4"
} }
issue_4831_1: {
options = {
properties: true,
}
input: {
console.log({
f() {
return arguments;
},
}.f("PASS")[0]);
}
expect: {
console.log([
function() {
return arguments;
},
][0]("PASS")[0]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4831_2: {
options = {
properties: true,
}
input: {
var f = {
f() {
return arguments;
},
}.f;
console.log(f("PASS")[0]);
}
expect: {
var f = {
f() {
return arguments;
},
}.f;
console.log(f("PASS")[0]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4888: {
options = {
properties: true,
}
input: {
console.log(typeof {
__proto__: 42,
}.__proto__);
}
expect: {
console.log(typeof {
__proto__: 42,
}.__proto__);
}
expect_stdout: "object"
}

View File

@@ -133,7 +133,7 @@ conditional: {
relational: { relational: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
foo() in new foo(); foo() in new foo();
@@ -158,7 +158,7 @@ relational: {
arithmetic: { arithmetic: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
foo() + foo(); foo() + foo();
@@ -183,7 +183,7 @@ arithmetic: {
boolean_and: { boolean_and: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
foo() && foo(); foo() && foo();
@@ -208,7 +208,7 @@ boolean_and: {
boolean_or: { boolean_or: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
foo() || foo(); foo() || foo();
@@ -233,7 +233,7 @@ boolean_or: {
assign: { assign: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
var a; var a;
@@ -256,7 +256,7 @@ assign: {
unary: { unary: {
options = { options = {
pure_funcs: [ "foo" ], pure_funcs: [ "foo" ],
side_effects :true, side_effects: true,
} }
input: { input: {
typeof foo(); typeof foo();

View File

@@ -1564,3 +1564,103 @@ issue_4803: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
nested_property_assignments_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var f;
((f = function() {
console.log("FAIL");
}).p = f).q = console.log("PASS");
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
nested_property_assignments_2: {
options = {
pure_getters: "strict",
unused: true,
}
input: {
var o = {};
(function() {
var a;
(o.p = a = {}).q = "PASS";
})();
console.log(o.p.q);
}
expect: {
var o = {};
(function() {
(o.p = {}).q = "PASS";
})();
console.log(o.p.q);
}
expect_stdout: "PASS"
}
nested_property_assignments_3: {
options = {
collapse_vars: true,
pure_getters: true,
side_effects: true,
unused: true,
}
input: {
var o = { p: {} };
(function(a) {
console && a;
if (console) {
a = a.p;
a.q = a;
}
})(o);
console.log(o.p.q === o.p ? "PASS" : "FAIL");
}
expect: {
var o = { p: {} };
(function(a) {
console;
if (console)
(a = a.p).q = a;
})(o);
console.log(o.p.q === o.p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_4939: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({
__proto__: {
get p() {
console.log("PASS");
},
},
}).p;
}
expect: {
({
__proto__: {
get p() {
console.log("PASS");
},
},
}).p;
}
expect_stdout: "PASS"
}

View File

@@ -2071,72 +2071,6 @@ issue_1670_2: {
} }
issue_1670_3: { issue_1670_3: {
options = {
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
switches: true,
typeofs: true,
unused: true,
}
input: {
(function f() {
switch (1) {
case 0:
var a = true;
break;
case 1:
if (typeof a === "undefined") console.log("PASS");
else console.log("FAIL");
}
})();
}
expect: {
(function() {
var a;
void 0 === a ? console.log("PASS") : console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
issue_1670_4: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
(function f() {
switch (1) {
case 0:
var a = true;
break;
case 1:
if (typeof a === "undefined") console.log("PASS");
else console.log("FAIL");
}
})();
}
expect: {
(function() {
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_1670_5: {
options = { options = {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
@@ -2168,7 +2102,7 @@ issue_1670_5: {
expect_stdout: "1" expect_stdout: "1"
} }
issue_1670_6: { issue_1670_4: {
options = { options = {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
@@ -7631,3 +7565,114 @@ issue_4568: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_4937: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
while (console.log("PASS"));
}
do {
function g() {
f();
}
} while (!g);
f();
}
expect: {
function f() {
while (console.log("PASS"));
}
do {
function g() {
f();
}
} while (!g);
f();
}
expect_stdout: "PASS"
}
issue_4943_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a, b = 1;
(function f() {
a = "foo";
b-- && f();
console.log(a);
a = "bar";
})();
}
expect: {
var a, b = 1;
(function f() {
a = "foo";
b-- && f();
console.log(a);
a = "bar";
})();
}
expect_stdout: [
"foo",
"bar",
]
}
issue_4943_2: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a, b = 1;
(function f() {
a = "foo";
b-- && f();
console.log(a);
a = "bar";
})();
}
expect: {
var a, b = 1;
(function f() {
a = "foo";
b-- && f();
console.log(a);
a = "bar";
})();
}
expect_stdout: [
"foo",
"bar",
]
}
issue_4949: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
a = 0;
console.log(a++, arguments[0]);
})(0);
}
expect: {
(function(a) {
a = 0;
console.log(a++, arguments[0]);
})(0);
}
expect_stdout: "0 1"
}

View File

@@ -198,6 +198,36 @@ global_fns: {
] ]
} }
global_constructors: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Map;
new Map(console.log("foo"));
Set;
new Set(console.log("bar"));
WeakMap;
new WeakMap(console.log("baz"));
WeakSet;
new WeakSet(console.log("moo"));
}
expect: {
console.log("foo");
console.log("bar");
console.log("baz");
console.log("moo");
}
expect_stdout: [
"foo",
"bar",
"baz",
"moo",
]
node_version: ">=0.12"
}
unsafe_builtin_1: { unsafe_builtin_1: {
options = { options = {
side_effects: true, side_effects: true,

View File

@@ -1045,3 +1045,134 @@ issue_4614: {
expect_stdout: true expect_stdout: true
node_version: ">=6" node_version: ">=6"
} }
issue_4849: {
options = {
reduce_vars: true,
unused: true,
}
input: {
while (function() {
while (!console);
}(new function(a) {
console.log(typeof { ...a });
}(function() {})));
}
expect: {
while (function() {
while (!console);
}(function(a) {
console.log(typeof { ...function() {} });
}()));
}
expect_stdout: "object"
node_version: ">=8"
}
issue_4882_1: {
options = {
objects: true,
spreads: true,
}
input: {
var o = {
p: "PASS",
... {
__proto__: {
p: "FAIL 1",
q: "FAIL 2",
},
},
};
console.log(o.p);
console.log(o.q);
}
expect: {
var o = {
p: "PASS",
};
console.log(o.p);
console.log(o.q);
}
expect_stdout: [
"PASS",
"undefined",
]
node_version: ">=8"
}
issue_4882_2: {
options = {
objects: true,
spreads: true,
}
input: {
console.log(null == Object.getPrototypeOf({
... {
__proto__: (console.log(42), null),
},
}) ? "FAIL" : "PASS");
}
expect: {
console.log(null == Object.getPrototypeOf({
... {
__proto__: (console.log(42), null),
},
}) ? "FAIL" : "PASS");
}
expect_stdout: [
"42",
"PASS",
]
node_version: ">=8"
}
issue_4882_3: {
options = {
objects: true,
spreads: true,
}
input: {
var o = {
__proto__: { p: 42 },
... {
set __proto__(v) {},
},
};
console.log(o.__proto__ === Object.getPrototypeOf(o) ? "FAIL" : "PASS");
console.log(o.p);
}
expect: {
var o = {
__proto__: { p: 42 },
["__proto__"]: void 0,
};
console.log(o.__proto__ === Object.getPrototypeOf(o) ? "FAIL" : "PASS");
console.log(o.p);
}
expect_stdout: [
"PASS",
"42",
]
node_version: ">=8"
}
issue_5006: {
options = {
arguments: true,
}
input: {
console.log(function(b, c) {
c = "FAIL 2";
return arguments[1];
}(...[], "FAIL 1") || "PASS");
}
expect: {
console.log(function(b, c) {
c = "FAIL 2";
return arguments[1];
}(...[], "FAIL 1") || "PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -113,7 +113,7 @@ constant_switch_5: {
// the break inside the if ruins our job // the break inside the if ruins our job
// we can still get rid of irrelevant cases. // we can still get rid of irrelevant cases.
switch (1) { switch (1) {
case 1: default:
x(); x();
if (foo) break; if (foo) break;
y(); y();
@@ -300,6 +300,37 @@ drop_default_2: {
} }
} }
drop_default_3: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
function f() {
console.log("PASS");
return 42;
}
switch (42) {
case f():
break;
case void console.log("FAIL"):
default:
}
}
expect: {
function f() {
console.log("PASS");
return 42;
}
switch (42) {
case f():
case void console.log("FAIL"):
}
}
expect_stdout: "PASS"
}
keep_default: { keep_default: {
options = { options = {
dead_code: true, dead_code: true,
@@ -423,7 +454,6 @@ drop_case_3: {
switch ({}.p) { switch ({}.p) {
default: default:
case void 0: case void 0:
break;
case c = "FAIL": case c = "FAIL":
} }
console.log(c); console.log(c);
@@ -454,7 +484,168 @@ drop_case_4: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
keep_case: { drop_case_5: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (42) {
case void console.log("PASS 1"):
console.log("FAIL 1");
case 42:
case console.log("FAIL 2"):
console.log("PASS 2");
}
}
expect: {
switch (42) {
default:
void console.log("PASS 1");
console.log("PASS 2");
}
}
expect_stdout: [
"PASS 1",
"PASS 2",
]
}
drop_case_6: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (console.log("PASS 1"), 2) {
case 0:
console.log("FAIL 1");
case (console.log("PASS 2"), 1):
console.log("FAIL 2");
}
}
expect: {
switch (console.log("PASS 1"), 2) {
case (console.log("PASS 2"), 1):
}
}
expect_stdout: [
"PASS 1",
"PASS 2",
]
}
drop_case_7: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (2) {
case 0:
console.log("FAIL 1");
case (console.log("PASS 1"), 1):
console.log("FAIL 2");
case 2:
console.log("PASS 2");
}
}
expect: {
switch (2) {
default:
console.log("PASS 1"), 1;
console.log("PASS 2");
}
}
expect_stdout: [
"PASS 1",
"PASS 2",
]
}
drop_case_8: {
options = {
dead_code: true,
switches: true,
}
input: {
function log(msg) {
console.log(msg);
return msg;
}
switch (log("foo")) {
case "bar":
log("moo");
break;
case log("baz"):
log("moo");
break;
default:
log("moo");
}
}
expect: {
function log(msg) {
console.log(msg);
return msg;
}
switch (log("foo")) {
case "bar":
case log("baz"):
default:
log("moo");
}
}
expect_stdout: [
"foo",
"baz",
"moo",
]
}
drop_case_9: {
options = {
dead_code: true,
switches: true,
}
input: {
function log(msg) {
console.log(msg);
return msg;
}
switch (log("foo")) {
case log("bar"):
log("moo");
break;
case "baz":
log("moo");
break;
default:
log("moo");
}
}
expect: {
function log(msg) {
console.log(msg);
return msg;
}
switch (log("foo")) {
default:
log("bar");
log("moo");
}
}
expect_stdout: [
"foo",
"bar",
"moo",
]
}
keep_case_1: {
options = { options = {
dead_code: true, dead_code: true,
switches: true, switches: true,
@@ -474,6 +665,76 @@ keep_case: {
} }
} }
keep_case_2: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch ("foo") {
case console.log("bar"):
case console.log("baz"), "moo":
}
}
expect: {
switch ("foo") {
case console.log("bar"):
case console.log("baz"), "moo":
}
}
expect_stdout: [
"bar",
"baz",
]
}
keep_case_3: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a;
switch (void console.log("PASS")) {
case a:
case console.log("FAIL"), 42:
}
}
expect: {
var a;
switch (void console.log("PASS")) {
case a:
case console.log("FAIL"), 42:
}
}
expect_stdout: "PASS"
}
keep_case_4: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a;
switch (void console.log("PASS")) {
case a:
case void console.log("FAIL"):
}
}
expect: {
var a;
switch (void console.log("PASS")) {
case a:
case void console.log("FAIL"):
}
}
expect_stdout: "PASS"
}
issue_376: { issue_376: {
options = { options = {
dead_code: true, dead_code: true,
@@ -661,7 +922,7 @@ issue_1680_1: {
case f(0): case f(0):
case f(1): case f(1):
f(2); f(2);
case 2: default:
f(5); f(5);
} }
} }
@@ -924,7 +1185,6 @@ issue_2535: {
} }
expect: { expect: {
w(), 42; w(), 42;
42;
y(); y();
z(); z();
} }
@@ -950,7 +1210,6 @@ issue_1750: {
expect: { expect: {
var a = 0, b = 1; var a = 0, b = 1;
true; true;
a, true;
b = 2; b = 2;
console.log(a, b); console.log(a, b);
} }
@@ -1088,7 +1347,8 @@ drop_switch_6: {
} }
} }
expect: { expect: {
A === B; A;
B;
x(); x();
C !== D; C !== D;
y(); y();
@@ -1181,3 +1441,170 @@ issue_4059: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5008_1: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
switches: true,
unsafe: true,
}
input: {
console.log(function f() {
switch (f) {
case f:
return "PASS";
default:
return "FAIL";
}
}());
}
expect: {
console.log(function f() {
switch (f) {
default:
return "PASS";
}
}());
}
expect_stdout: "PASS"
}
issue_5008_2: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
switches: true,
unsafe: true,
}
input: {
console.log(function(a) {
switch (a) {
case a:
return "PASS";
default:
return "FAIL";
}
}([]));
}
expect: {
console.log(function(a) {
switch (a) {
default:
return "PASS";
}
}([]));
}
expect_stdout: "PASS"
}
issue_5008_3: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
switches: true,
unsafe: true,
}
input: {
console.log(function(a) {
switch (a) {
case a:
return "PASS";
default:
return "FAIL";
}
}({}));
}
expect: {
console.log(function(a) {
switch (a) {
default:
return "PASS";
}
}({}));
}
expect_stdout: "PASS"
}
issue_5008_4: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
switches: true,
}
input: {
console.log(function(a) {
switch (a) {
case a:
return "PASS";
default:
return "FAIL";
}
}(/foo/));
}
expect: {
console.log(function(a) {
switch (a) {
default:
return "PASS";
}
}(/foo/));
}
expect_stdout: "PASS"
}
issue_5010: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a;
switch (42) {
case console.log("PASS"):
case a:
console.log("FAIL");
case 42:
}
}
expect: {
var a;
switch (42) {
case console.log("PASS"):
case a:
console.log("FAIL");
}
}
expect_stdout: "PASS"
}
issue_5012: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (void 0) {
case console.log("PASS"):
break;
case void 0:
case 42:
console.log("FAIL");
}
}
expect: {
switch (void 0) {
case console.log("PASS"):
break;
default:
console.log("FAIL");
}
}
expect_stdout: "PASS"
}

View File

@@ -62,6 +62,23 @@ tag_parentheses_arrow: {
node_version: ">=4" node_version: ">=4"
} }
tag_parentheses_binary: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var f = function() {
console.log("PASS");
} || console
f``;
}
expect_exact: '(function(){console.log("PASS")}||console)``;'
expect_stdout: "PASS"
node_version: ">=4"
}
tag_parentheses_new: { tag_parentheses_new: {
input: { input: {
(new function() { (new function() {
@@ -87,6 +104,21 @@ tag_parentheses_sequence: {
node_version: ">=4" node_version: ">=4"
} }
tag_parentheses_unary: {
input: {
var a;
try {
(~a)``;
(a++)``;
} catch (e) {
console.log("PASS");
}
}
expect_exact: 'var a;try{(~a)``;(a++)``}catch(e){console.log("PASS")}'
expect_stdout: "PASS"
node_version: ">=4"
}
malformed_escape: { malformed_escape: {
input: { input: {
(function(s) { (function(s) {
@@ -283,6 +315,21 @@ unsafe_side_effects: {
node_version: ">=4" node_version: ">=4"
} }
pure_funcs: {
options = {
pure_funcs: "Math.random",
side_effects: true,
}
input: {
Math.random`${console.log("PASS")}`;
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4604: { issue_4604: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -343,7 +390,7 @@ issue_4676: {
reduce_vars: true, reduce_vars: true,
templates: true, templates: true,
toplevel: true, toplevel: true,
unsafe:true, unsafe: true,
unused: true, unused: true,
} }
input: { input: {
@@ -366,3 +413,24 @@ issue_4676: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=4" node_version: ">=4"
} }
issue_4931: {
options = {
evaluate: true,
templates: true,
unsafe: true,
}
input: {
console.log(String.raw`${typeof A} ${"\r"}`);
console.log(String.raw`${"\\"} ${"`"}`);
}
expect: {
console.log(String.raw`${typeof A} ${"\r"}`);
console.log("\\ `");
}
expect_stdout: [
"undefined \r",
"\\ `",
]
node_version: ">=4"
}

View File

@@ -523,3 +523,93 @@ default_init: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=4" node_version: ">=4"
} }
issue_4933_1: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
console.log(f());
function f() {
var a;
for (console in a = [ f ]) {
const b = a;
}
}
}
expect: {
console.log(function f() {
var a;
for (console in a = [ f ]) {
const b = a;
}
}());
}
expect_stdout: "undefined"
}
issue_4933_2: {
options = {
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
console.log(f());
function f() {
var a;
for (console in a = [ f ]) {
const b = a;
}
}
}
expect: {
console.log(function f() {
for (console in [ f ]);
}());
}
expect_stdout: "undefined"
}
issue_4954: {
options = {
functions: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
"use strict";
(function() {
{
let a = console;
console.log(typeof a);
}
{
let a = function() {};
a && console.log(typeof a);
}
})();
}
expect: {
"use strict";
(function() {
var a = console;
console.log(typeof a);
{
let a = function() {};
a && console.log(typeof a);
}
})();
}
expect_stdout: [
"object",
"function",
]
node_version: ">=4"
}

View File

@@ -150,6 +150,27 @@ for_await_of: {
node_version: ">=10" node_version: ">=10"
} }
comment_newline: {
beautify = {
comments: "all",
}
input: {
console.log(function*() {
yield (
/* */
"PASS"
);
}().next().value);
}
expect_exact: [
"console.log(function*(){",
"/* */",
'yield"PASS"}().next().value);',
]
expect_stdout: "PASS"
node_version: ">=4"
}
collapse_vars_1: { collapse_vars_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -1062,3 +1083,166 @@ issue_4769_2: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
} }
issue_5019_1: {
options = {
dead_code: true,
}
input: {
(function(a) {
return a = function*() {
console.log(typeof a);
}();
})().next();
}
expect: {
(function(a) {
return a = function*() {
console.log(typeof a);
}();
})().next();
}
expect_stdout: "object"
node_version: ">=4"
}
issue_5019_2: {
options = {
inline: true,
toplevel: true,
}
input: {
var a = [];
for (var b in "foo")
a.push(function(c) {
return function*() {
console.log(c);
}();
}(b));
a.map(function(d) {
return d.next();
});
}
expect: {
var a = [];
for (var b in "foo")
a.push(function(c) {
return function*() {
console.log(c);
}();
}(b));
a.map(function(d) {
return d.next();
});
}
expect_stdout: [
"0",
"1",
"2",
]
node_version: ">=4"
}
issue_5032_normal: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(c) {
var b = log(c), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5032_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5034: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
var yield = function f() {
return function*() {
return f;
};
};
return yield()().next().value === yield;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function() {
var yield = function f() {
return function*() {
return f;
};
};
return yield()().next().value === yield;
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -1 +1 @@
++null console.log(4 || (null = 4));

View File

@@ -0,0 +1 @@
console.log(5 || ([]?.length ^= 5));

View File

@@ -0,0 +1 @@
for await (; console.log(42););

View File

@@ -58,22 +58,29 @@ if (typeof phantom == "undefined") {
}).listen(); }).listen();
server.on("listening", function() { server.on("listening", function() {
var port = server.address().port; var port = server.address().port;
if (debug) { if (debug) return console.log("http://localhost:" + port + "/");
console.log("http://localhost:" + port + "/"); var cmd = process.platform == "win32" ? "npm.cmd" : "npm";
} else (function install() {
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [ function npm(args, done) {
child_process.spawn(cmd, args, { stdio: [ "ignore", 1, 2 ] }).on("exit", done);
}
(function install() {
npm([
"install", "install",
"phantomjs-prebuilt@2.1.14", "phantomjs-prebuilt@2.1.14",
"--no-audit", "--no-audit",
"--no-optional", "--no-optional",
"--no-save", "--no-save",
"--no-update-notifier", "--no-update-notifier",
], { ], function(code) {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
if (code) { if (code) {
console.log("npm install failed with code", code); console.log("npm install failed with code", code);
return install(); return npm([
"cache",
"clean",
"--force",
], install);
} }
var program = require("phantomjs-prebuilt").exec(process.argv[1], port); var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
program.stdout.pipe(process.stdout); program.stdout.pipe(process.stdout);

View File

@@ -427,16 +427,30 @@ describe("bin/uglifyjs", function() {
done(); done();
}); });
}); });
it("Should throw syntax error (++null)", function(done) { it("Should throw syntax error (null = 4)", function(done) {
var command = uglifyjscmd + " test/input/invalid/assign_4.js"; var command = uglifyjscmd + " test/input/invalid/assign_4.js";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_4.js:1,0", "Parse error at test/input/invalid/assign_4.js:1,23",
"++null", "console.log(4 || (null = 4));",
"^", " ^",
"ERROR: Invalid use of ++ operator", "ERROR: Invalid assignment",
].join("\n"));
done();
});
});
it("Should throw syntax error ([]?.length ^= 5)", function(done) {
var command = uglifyjscmd + " test/input/invalid/assign_5.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_5.js:1,29",
"console.log(5 || ([]?.length ^= 5));",
" ^",
"ERROR: Invalid assignment",
].join("\n")); ].join("\n"));
done(); done();
}); });
@@ -679,6 +693,20 @@ describe("bin/uglifyjs", function() {
done(); done();
}); });
}); });
it("Should throw syntax error (for-await)", function(done) {
var command = uglifyjscmd + " test/input/invalid/for-await.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/for-await.js:1,11",
"for await (; console.log(42););",
" ^",
"ERROR: Unexpected token: punc «;»",
].join("\n"));
done();
});
});
it("Should throw syntax error (switch defaults)", function(done) { it("Should throw syntax error (switch defaults)", function(done) {
var command = uglifyjscmd + " test/input/invalid/switch.js"; var command = uglifyjscmd + " test/input/invalid/switch.js";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {

View File

@@ -7,11 +7,11 @@ describe("let", function() {
// Produce a lot of variables in a function and run it through mangle. // Produce a lot of variables in a function and run it through mangle.
var s = '"dddddeeeeelllllooooottttt"; function foo() {'; var s = '"dddddeeeeelllllooooottttt"; function foo() {';
for (var i = 0; i < 18000; i++) { for (var i = 0; i < 18000; i++) {
s += "var v" + i + "=0;"; s += "var v" + i + "=[];";
} }
s += '}'; s += '}';
var result = UglifyJS.minify(s, { var result = UglifyJS.minify(s, {
compress: false compress: false,
}).code; }).code;
// Verify that select keywords and reserved keywords not produced // Verify that select keywords and reserved keywords not produced

View File

@@ -183,6 +183,24 @@ describe("test/reduce.js", function() {
"// }", "// }",
].join("\n")); ].join("\n"));
}); });
it("Should reduce `for (const ... in ...)` without invalid intermediate AST", function() {
if (semver.satisfies(process.version, "<4")) return;
var code = [
"var a = 0;",
"",
"for (const b in [ 1, 2, 3 ]) {",
" a = +a + 1 - .2;",
" console.log(a);",
"}",
].join("\n");
var result = reduce_test(code, {
compress: {
unsafe_math: true,
},
});
if (result.error) throw result.error;
assert.deepEqual(result.warnings, []);
});
it("Should reduce infinite loops with reasonable performance", function() { it("Should reduce infinite loops with reasonable performance", function() {
if (semver.satisfies(process.version, "<=0.10")) return; if (semver.satisfies(process.version, "<=0.10")) return;
this.timeout(120000); this.timeout(120000);
@@ -379,4 +397,21 @@ describe("test/reduce.js", function() {
"// }", "// }",
].join("\n")); ].join("\n"));
}); });
it("Should reduce object with method syntax without invalid intermediate AST", function() {
if (semver.satisfies(process.version, "<4")) return;
var code = [
"console.log({",
" f() {",
" return 1 - .8;",
" },",
"}.f());",
].join("\n");
var result = reduce_test(code, {
compress: {
unsafe_math: true,
},
});
if (result.error) throw result.error;
assert.deepEqual(result.warnings, []);
});
}); });

View File

@@ -101,6 +101,19 @@ describe("sourcemaps", function() {
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
assert.deepEqual(map.names, []); assert.deepEqual(map.names, []);
}); });
it("Should mark class properties", function() {
var result = UglifyJS.minify([
"class A {",
" static P = 42",
" set #q(v) {}",
"}",
].join("\n"), {
sourceMap: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "class A{static P=42;set#q(s){}}");
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["A","P","#q","v"],"mappings":"MAAMA,EACFC,SAAW,GACXC,MAAOC"}');
});
it("Should mark array/object literals", function() { it("Should mark array/object literals", function() {
var result = UglifyJS.minify([ var result = UglifyJS.minify([
"var obj = {};", "var obj = {};",

View File

@@ -5,23 +5,23 @@ var acorn = require("acorn");
var ufuzz = require("./ufuzz"); var ufuzz = require("./ufuzz");
var UglifyJS = require(".."); var UglifyJS = require("..");
function try_beautify(code) { function beautify(ast) {
var beautified = UglifyJS.minify(code, { var beautified = UglifyJS.minify(ast, {
compress: false, compress: false,
mangle: false, mangle: false,
output: { output: {
beautify: true, beautify: true,
braces: true braces: true,
} },
});
if (beautified.error) return beautified;
return UglifyJS.minify(beautified.code, {
compress: false,
mangle: false,
output: {
ast: true,
},
}); });
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.log(code);
} else {
console.log("// (beautified)");
console.log(beautified.code);
}
} }
function validate(ast) { function validate(ast) {
@@ -35,16 +35,55 @@ function validate(ast) {
return UglifyJS.minify(ast, { return UglifyJS.minify(ast, {
compress: false, compress: false,
mangle: false, mangle: false,
output: {
ast: true,
},
validate: true,
}); });
} }
function test(original, estree, description) { function patch_import(code) {
var transformed = validate(UglifyJS.AST_Node.from_mozilla_ast(estree)); return code.replace(/\bimport\s*\{\s*\}\s*from\s*(['"])/g, "import$1")
if (transformed.error || original !== transformed.code) { .replace(/\b(import\b.*?)\s*,\s*\{\s*\}\s*(from\s*['"])/g, "$1 $2");
}
function equals(input, transformed) {
if (input.code === transformed.code) return true;
return patch_import(input.code) === patch_import(transformed.code);
}
function test(input, to_moz, description, skip_on_error, beautified) {
try {
var ast = UglifyJS.AST_Node.from_mozilla_ast(to_moz(input));
} catch (e) {
if (skip_on_error) return true;
console.log("//=============================================================");
console.log("//", description, "failed... round", round);
console.log(e);
console.log("// original code");
if (beautified === true) console.log("// (beautified)");
console.log(input.code);
return false;
}
var transformed = validate(ast);
if (transformed.error || !equals(input, transformed)) {
if (!beautified) {
beautified = beautify(input.ast);
if (!beautified.error) {
beautified.raw = beautified.code;
if (!test(beautified, to_moz, description, skip_on_error, true)) return false;
}
}
console.log("//============================================================="); console.log("//=============================================================");
console.log("// !!!!!! Failed... round", round); console.log("// !!!!!! Failed... round", round);
console.log("// original code"); console.log("// original code");
try_beautify(original); if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
} else if (beautified === true) {
console.log("// (beautified)");
}
console.log(input.raw);
console.log(); console.log();
console.log(); console.log();
console.log("//-------------------------------------------------------------"); console.log("//-------------------------------------------------------------");
@@ -52,7 +91,15 @@ function test(original, estree, description) {
if (transformed.error) { if (transformed.error) {
console.log(transformed.error.stack); console.log(transformed.error.stack);
} else { } else {
try_beautify(transformed.code); beautified = beautify(transformed.ast);
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.log(transformed.code);
} else {
console.log("// (beautified)");
console.log(beautified.code);
}
} }
console.log("!!!!!! Failed... round", round); console.log("!!!!!! Failed... round", round);
return false; return false;
@@ -67,24 +114,33 @@ for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r"); process.stdout.write(round + " of " + num_iterations + "\r");
var code = ufuzz.createTopLevelCode(); var code = ufuzz.createTopLevelCode();
minify_options.forEach(function(options) { minify_options.forEach(function(options) {
var input = options ? UglifyJS.minify(code, JSON.parse(options)).code : code; var ok = true;
var uglified = UglifyJS.minify(input, { var input = UglifyJS.minify(options ? UglifyJS.minify(code, JSON.parse(options)).code : code, {
compress: false, compress: false,
mangle: false, mangle: false,
output: { output: {
ast: true ast: true,
} },
}); });
var ok = test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()"); input.raw = options ? input.code : code;
try { if (input.error) {
ok = test(uglified.code, acorn.parse(input), "acorn.parse()") && ok; ok = false;
} catch (e) {
console.log("//============================================================="); console.log("//=============================================================");
console.log("// acorn parser failed... round", round); console.log("// minify() failed... round", round);
console.log(e); console.log(input.error);
console.log("// original code"); console.log("// original code");
console.log(input); console.log(code);
} }
if (ok) ok = test(input, function(input) {
return input.ast.to_mozilla_ast();
}, "AST_Node.to_mozilla_ast()");
if (ok) ok = test(input, function(input) {
return acorn.parse(input.raw, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
});
}, "acorn.parse()", !ufuzz.verbose);
if (!ok) process.exit(1); if (!ok) process.exit(1);
}); });
} }

View File

@@ -46,7 +46,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
if (verbose) { if (verbose) {
log("// Node.js " + process.version + " on " + os.platform() + " " + os.arch()); log("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
} }
if (differs.error && [ "DefaultsError", "SyntaxError" ].indexOf(differs.error.name) < 0) { if (differs && differs.error && [ "DefaultsError", "SyntaxError" ].indexOf(differs.error.name) < 0) {
test_for_diff = test_minify; test_for_diff = test_minify;
differs = test_for_diff(testcase, minify_options, result_cache, max_timeout); differs = test_for_diff(testcase, minify_options, result_cache, max_timeout);
} }
@@ -132,6 +132,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return; return;
} }
if (parent instanceof U.AST_VarDef && parent.name === node) return; if (parent instanceof U.AST_VarDef && parent.name === node) return;
// preserve class methods
if (parent instanceof U.AST_ClassMethod && parent.value === node) return;
// preserve exports // preserve exports
if (parent instanceof U.AST_ExportDeclaration) return; if (parent instanceof U.AST_ExportDeclaration) return;
if (parent instanceof U.AST_ExportDefault) return; if (parent instanceof U.AST_ExportDefault) return;
@@ -147,6 +149,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node; if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
// preserve for (xxx in/of ...) // preserve for (xxx in/of ...)
if (parent instanceof U.AST_ForEnumeration && parent.init === node) return node; if (parent instanceof U.AST_ForEnumeration && parent.init === node) return node;
// preserve super(...)
if (node.TYPE == "Call" && node.expression instanceof U.AST_Super) return;
if (node instanceof U.AST_Super && parent.TYPE == "Call" && parent.expression === node) return node;
// node specific permutations with no parent logic // node specific permutations with no parent logic
@@ -316,10 +321,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
var expr; var expr;
switch ((node.start._permute * steps | 0) % 3) { switch ((node.start._permute * steps | 0) % 3) {
case 0: case 0:
if (!(node.init instanceof U.AST_Definitions if (node.init instanceof U.AST_Definitions) {
&& node.init.definitions[0].name instanceof U.AST_Destructured)) { if (node.init instanceof U.AST_Const) break;
expr = node.init; if (node.init.definitions[0].name instanceof U.AST_Destructured) break;
} }
expr = node.init;
break; break;
case 1: case 1:
expr = node.object; expr = node.object;
@@ -484,23 +490,27 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
CHANGED = true; CHANGED = true;
return newNode; return newNode;
}, function(node, in_list) { }, function(node, in_list) {
if (node instanceof U.AST_Sequence) { if (node instanceof U.AST_Definitions) {
// remove empty var statement
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
start: {},
});
} else if (node instanceof U.AST_ObjectMethod) {
if (!/Function$/.test(node.value.TYPE)) return new U.AST_ObjectKeyVal({
key: node.key,
value: node.value,
start: {},
});
} else if (node instanceof U.AST_Sequence) {
// expand single-element sequence // expand single-element sequence
if (node.expressions.length == 1) return node.expressions[0]; if (node.expressions.length == 1) return node.expressions[0];
} } else if (node instanceof U.AST_Try) {
else if (node instanceof U.AST_Try) {
// expand orphaned try block // expand orphaned try block
if (!node.bcatch && !node.bfinally) return new U.AST_BlockStatement({ if (!node.bcatch && !node.bfinally) return new U.AST_BlockStatement({
body: node.body, body: node.body,
start: {}, start: {},
}); });
} }
else if (node instanceof U.AST_Definitions) {
// remove empty var statement
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
start: {},
});
}
}); });
var diff_error_message; var diff_error_message;

View File

@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/acorn \ rm -rf tmp/acorn \
&& git clone https://github.com/acornjs/acorn.git tmp/acorn \ && git clone https://github.com/acornjs/acorn.git tmp/acorn \
&& cd tmp/acorn \ && cd tmp/acorn \
@@ -89,7 +96,7 @@ minify_in_situ "acorn/src" \
&& minify_in_situ "acorn-loose/src" \ && minify_in_situ "acorn-loose/src" \
&& minify_in_situ "acorn-walk/src" \ && minify_in_situ "acorn-walk/src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm install \ && npm_install \
&& rm -rf acorn/dist acorn-loose/dist acorn-walk/dist \ && rm -rf acorn/dist acorn-loose/dist acorn-walk/dist \
&& npm run build \ && npm run build \
&& minify_in_situ "acorn/dist" \ && minify_in_situ "acorn/dist" \

View File

@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/bootstrap \ rm -rf tmp/bootstrap \
&& git clone --depth 1 --branch v5.0.0-beta2 https://github.com/twbs/bootstrap.git tmp/bootstrap \ && git clone --depth 1 --branch v5.0.0-beta2 https://github.com/twbs/bootstrap.git tmp/bootstrap \
&& cd tmp/bootstrap \ && cd tmp/bootstrap \
@@ -171,7 +178,7 @@ rm -rf tmp/bootstrap \
EOF EOF
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
rm -rf node_modules \ rm -rf node_modules \
&& npm ci \ && npm_install \
&& minify_in_situ "node_modules/@popperjs/core" \ && minify_in_situ "node_modules/@popperjs/core" \
&& rm -rf dist/js/* \ && rm -rf dist/js/* \
&& minify_in_situ "build" \ && minify_in_situ "build" \

View File

@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/buble \ rm -rf tmp/buble \
&& git clone https://github.com/bublejs/buble.git tmp/buble \ && git clone https://github.com/bublejs/buble.git tmp/buble \
&& cd tmp/buble \ && cd tmp/buble \
@@ -38,7 +45,7 @@ EOF
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
minify_in_situ "src" \ minify_in_situ "src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm ci \ && npm_install \
&& rm -rf dist \ && rm -rf dist \
&& npm run build \ && npm run build \
&& minify_in_situ "dist" \ && minify_in_situ "dist" \

View File

@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/butternut \ rm -rf tmp/butternut \
&& git clone https://github.com/Rich-Harris/butternut.git tmp/butternut \ && git clone https://github.com/Rich-Harris/butternut.git tmp/butternut \
&& cd tmp/butternut \ && cd tmp/butternut \
@@ -38,7 +45,7 @@ EOF
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
minify_in_situ "src" \ minify_in_situ "src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm install \ && npm_install \
&& rm -rf dist \ && rm -rf dist \
&& npm run build \ && npm run build \
&& minify_in_situ "dist" \ && minify_in_situ "dist" \

View File

@@ -36,7 +36,9 @@ EOF
} }
if [ $NATIVE ]; then unset -f timeout; fi if [ $NATIVE ]; then unset -f timeout; fi
git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs while !(git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs); do
rm -rf ~/.nvs
done
while ! timeout 60 bash -c ". ~/.nvs/nvs.sh add $NODE && nvs use $NODE"; do while ! timeout 60 bash -c ". ~/.nvs/nvs.sh add $NODE && nvs use $NODE"; do
cd ~/.nvs cd ~/.nvs
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
@@ -51,4 +53,6 @@ npm config set save false
npm config set strict-ssl false npm config set strict-ssl false
npm config set update-notifier false npm config set update-notifier false
npm --version npm --version
while !(npm install); do echo "'npm install' failed - retrying..."; done while !(npm install); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done

View File

@@ -18,6 +18,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/mathjs \ rm -rf tmp/mathjs \
&& git clone --depth 1 --branch v9.2.0 https://github.com/josdejong/mathjs.git tmp/mathjs \ && git clone --depth 1 --branch v9.2.0 https://github.com/josdejong/mathjs.git tmp/mathjs \
&& cd tmp/mathjs \ && cd tmp/mathjs \
@@ -191,7 +198,7 @@ minify_in_situ "bin" \
&& minify_in_situ "test" \ && minify_in_situ "test" \
&& minify_in_situ "tools" \ && minify_in_situ "tools" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm ci \ && npm_install \
&& rm -rf lib \ && rm -rf lib \
&& npm run build \ && npm run build \
&& minify_in_situ "lib" \ && minify_in_situ "lib" \

View File

@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/rollup \ rm -rf tmp/rollup \
&& git clone https://github.com/rollup/rollup.git tmp/rollup \ && git clone https://github.com/rollup/rollup.git tmp/rollup \
&& cd tmp/rollup \ && cd tmp/rollup \
@@ -77,7 +84,7 @@ minify_in_situ "bin" \
&& minify_in_situ "browser" \ && minify_in_situ "browser" \
&& minify_in_situ "src" \ && minify_in_situ "src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm ci \ && npm_install \
&& rm -rf dist \ && rm -rf dist \
&& npm run build \ && npm run build \
&& minify_in_situ "dist" \ && minify_in_situ "dist" \

View File

@@ -6,17 +6,28 @@ UGLIFY_OPTIONS=$@
minify_in_situ() { minify_in_situ() {
ARGS="$UGLIFY_OPTIONS --validate --in-situ" ARGS="$UGLIFY_OPTIONS --validate --in-situ"
DIRS="$1" DIRS="$1"
echo '> esbuild' $DIRS
for i in `find $DIRS -type f -name '*.ts' | grep -v '\.d\.ts'`
do
echo "$i"
CODE=`cat "$i"`
node_modules/.bin/esbuild --loader=ts --target=esnext > "$i" <<EOF
$CODE
EOF
ARGS="$ARGS $i"
done
echo '> uglify-js' $DIRS $UGLIFY_OPTIONS echo '> uglify-js' $DIRS $UGLIFY_OPTIONS
for i in `find $DIRS -type f -name '*.js'` for i in `find $DIRS -type f -name '*.js'`
do do
ARGS="$ARGS $i" ARGS="$ARGS $i"
done done
uglify-js $ARGS uglify-js $ARGS
for i in `find $DIRS -type f -name '*.ts' | grep -v '\.d\.ts'` }
do
echo "$i" npm_install() {
node_modules/.bin/esbuild --loader=ts --target=node14 < "$i" \ PKG="$1"
| uglify-js $UGLIFY_OPTIONS -o "$i" while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done done
} }
@@ -32,6 +43,9 @@ rm -rf tmp/rollup \
- "postpublish": "pinst --enable", - "postpublish": "pinst --enable",
- "prepare": "npm run build", - "prepare": "npm run build",
- "prepublishOnly": "pinst --disable && npm ci && npm run lint:nofix && npm run security && npm run build:bootstrap && npm run test:all", - "prepublishOnly": "pinst --disable && npm ci && npm run lint:nofix && npm run security && npm run build:bootstrap && npm run test:all",
@@ -93 +89 @@
- "is-reference": "lukastaegert/is-reference#update-class-features",
+ "is-reference": "3.0.0",
--- a/test/cli/index.js --- a/test/cli/index.js
+++ b/test/cli/index.js +++ b/test/cli/index.js
@@ -13,0 +14,3 @@ sander.rimrafSync(__dirname, 'node_modules'); @@ -13,0 +14,3 @@ sander.rimrafSync(__dirname, 'node_modules');
@@ -40,11 +54,11 @@ rm -rf tmp/rollup \
+sander.rimrafSync(__dirname, 'samples', 'watch', 'watch-config-initial-error'); +sander.rimrafSync(__dirname, 'samples', 'watch', 'watch-config-initial-error');
EOF EOF
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
npm install esbuild-wasm@0.8.56 \ npm_install esbuild-wasm@0.8.56 \
&& minify_in_situ "cli" \ && minify_in_situ "cli" \
&& minify_in_situ "src" \ && minify_in_situ "src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm ci \ && npm_install \
&& rm -rf dist \ && rm -rf dist \
&& npm run build \ && npm run build \
&& minify_in_situ "dist" \ && minify_in_situ "dist" \

View File

@@ -6,6 +6,16 @@ UGLIFY_OPTIONS=$@
minify_in_situ() { minify_in_situ() {
ARGS="$UGLIFY_OPTIONS --validate --in-situ" ARGS="$UGLIFY_OPTIONS --validate --in-situ"
DIRS="$1" DIRS="$1"
echo '> esbuild' $DIRS
for i in `find $DIRS -type f -name '*.ts' | grep -v '\.d\.ts'`
do
echo "$i"
CODE=`cat "$i"`
node_modules/.bin/esbuild --loader=ts --target=esnext > "$i" <<EOF
$CODE
EOF
ARGS="$ARGS $i"
done
echo '> uglify-js' $DIRS $UGLIFY_OPTIONS echo '> uglify-js' $DIRS $UGLIFY_OPTIONS
for i in `find $DIRS -type f -name '*.js'` for i in `find $DIRS -type f -name '*.js'`
do do
@@ -16,11 +26,12 @@ minify_in_situ() {
ARGS="$ARGS $i" ARGS="$ARGS $i"
done done
uglify-js $ARGS uglify-js $ARGS
for i in `find $DIRS -type f -name '*.ts' | grep -v '\.d\.ts'` }
do
echo "$i" npm_install() {
node_modules/.bin/esbuild --loader=ts --target=node14 < "$i" \ PKG="$1"
| uglify-js $UGLIFY_OPTIONS -o "$i" while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done done
} }
@@ -79,10 +90,10 @@ rm -rf tmp/sucrase \
+export { getJSXPragmaInfo as HACK }; +export { getJSXPragmaInfo as HACK };
EOF EOF
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
npm install esbuild-wasm@0.8.56 \ npm_install esbuild-wasm@0.8.56 \
&& minify_in_situ "src" \ && minify_in_situ "src" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm install \ && npm_install \
&& npm run clean \ && npm run clean \
&& npm run build \ && npm run build \
&& minify_in_situ "dist" \ && minify_in_situ "dist" \

View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
alias uglify-js="node --max-old-space-size=4096 $PWD/bin/uglifyjs" alias uglify-js="node --max-old-space-size=8192 $PWD/bin/uglifyjs"
UGLIFY_OPTIONS=$@ UGLIFY_OPTIONS=$@
minify_in_situ() { minify_in_situ() {
@@ -14,6 +14,13 @@ minify_in_situ() {
uglify-js $ARGS uglify-js $ARGS
} }
npm_install() {
PKG="$1"
while !(npm install $PKG); do
while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done
done
}
rm -rf tmp/web-tooling-benchmark \ rm -rf tmp/web-tooling-benchmark \
&& git clone --depth 1 --branch v0.5.3 https://github.com/v8/web-tooling-benchmark.git tmp/web-tooling-benchmark \ && git clone --depth 1 --branch v0.5.3 https://github.com/v8/web-tooling-benchmark.git tmp/web-tooling-benchmark \
&& cd tmp/web-tooling-benchmark \ && cd tmp/web-tooling-benchmark \
@@ -23,6 +30,17 @@ rm -rf tmp/web-tooling-benchmark \
+++ b/package.json +++ b/package.json
@@ -12 +11,0 @@ @@ -12 +11,0 @@
- "postinstall": "npm run build:terser-bundled && npm run build:uglify-js-bundled && npm run build", - "postinstall": "npm run build:terser-bundled && npm run build:uglify-js-bundled && npm run build",
--- a/src/bootstrap.js
+++ b/src/bootstrap.js
@@ -6 +6 @@ const gmean = require("compute-gmean");
-const package = require("../package.json");
+const package_json = require("../package.json");
@@ -65 +65 @@ function initialize() {
- document.title = \`Web Tooling Benchmark v\${package.version}\`;
+ document.title = \`Web Tooling Benchmark v\${package_json.version}\`;
@@ -68 +68 @@ function initialize() {
- versionDiv.innerHTML = \`v\${package.version}\`;
+ versionDiv.innerHTML = \`v\${package_json.version}\`;
--- a/src/cli-flags-helper.js --- a/src/cli-flags-helper.js
+++ b/src/cli-flags-helper.js +++ b/src/cli-flags-helper.js
@@ -7 +6,0 @@ const targetList = new Set([ @@ -7 +6,0 @@ const targetList = new Set([
@@ -36,7 +54,7 @@ ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
minify_in_situ "src" \ minify_in_situ "src" \
&& minify_in_situ "third_party" \ && minify_in_situ "third_party" \
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm ci \ && npm_install \
&& rm -rf build/* \ && rm -rf build/* \
&& npm run build:terser-bundled \ && npm run build:terser-bundled \
&& npm run build:uglify-js-bundled \ && npm run build:uglify-js-bundled \

View File

@@ -27,8 +27,8 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
} : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) { } : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) {
if ([ if ([
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/, /\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
/\b(async[ \t]+function|setImmediate|setInterval|setTimeout)\b/, /\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/,
/\basync([ \t]+|[ \t]*\*[ \t]*)[^\s()[\]{},.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/, /\basync([ \t]+|[ \t]*#|[ \t]*\*[ \t]*)[^\s()[\]{},.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
].some(function(pattern) { ].some(function(pattern) {
return pattern.test(code); return pattern.test(code);
})) { })) {
@@ -55,6 +55,8 @@ exports.patch_module_statements = function(code) {
if (!header) return ""; if (!header) return "";
if (header.length == 1) return "0, " + header; if (header.length == 1) return "0, " + header;
return header.slice(0, -1) + " _" + ++count + header.slice(-1); return header.slice(0, -1) + " _" + ++count + header.slice(-1);
}).replace(/\bimport\.meta\b/g, function() {
return '({ url: "https://example.com/path/index.html" })';
}).replace(/\bimport\b(?:\s*([^('"]+)\bfrom\b)?\s*(['"]).*?\2(?:$|\n|;)/g, function(match, symbols) { }).replace(/\bimport\b(?:\s*([^('"]+)\bfrom\b)?\s*(['"]).*?\2(?:$|\n|;)/g, function(match, symbols) {
if (symbols) { if (symbols) {
if (!/^[{*]/.test(symbols)) symbols = "default:" + symbols; if (!/^[{*]/.test(symbols)) symbols = "default:" + symbols;
@@ -220,7 +222,7 @@ function setup(global, builtins, setup_log, setup_tty) {
if (arg === global) return "[object global]"; if (arg === global) return "[object global]";
if (/Error$/.test(arg.name)) return arg.toString(); if (/Error$/.test(arg.name)) return arg.toString();
if (typeof arg.then == "function") return "[object Promise]"; if (typeof arg.then == "function") return "[object Promise]";
arg.constructor.toString(); if (arg.constructor) arg.constructor.toString();
var index = cache.original.indexOf(arg); var index = cache.original.indexOf(arg);
if (index >= 0) return cache.replaced[index]; if (index >= 0) return cache.replaced[index];
if (--cache.level < 0) return "[object Object]"; if (--cache.level < 0) return "[object Object]";

View File

@@ -1,7 +1,7 @@
var get = require("https").get; var get = require("https").get;
var parse = require("url").parse; var parse = require("url").parse;
var base, token, run_number, eldest = true; var base, token, run_number;
exports.init = function(url, auth, num) { exports.init = function(url, auth, num) {
base = url; base = url;
token = auth; token = auth;
@@ -19,14 +19,14 @@ exports.should_stop = function(callback) {
do { do {
workflow = runs.pop(); workflow = runs.pop();
if (!workflow) return; if (!workflow) return;
if (workflow.event == "schedule" && workflow.run_number == run_number) found = true; if (is_cron(workflow) && workflow.run_number == run_number) found = true;
} while (!found && workflow.status == "completed"); } while (!found && workflow.status == "completed");
read(workflow.jobs_url, function(reply) { read(workflow.jobs_url, function(reply) {
if (!reply || !Array.isArray(reply.jobs)) return; if (!reply || !Array.isArray(reply.jobs)) return;
if (!reply.jobs.every(function(job) { if (!reply.jobs.every(function(job) {
if (job.status == "completed") return true; if (job.status == "completed") return true;
remaining--; remaining--;
return found || workflow.event != "schedule"; return found || !is_cron(workflow);
})) return; })) return;
if (remaining >= 0) { if (remaining >= 0) {
next(); next();
@@ -38,6 +38,10 @@ exports.should_stop = function(callback) {
}); });
}; };
function is_cron(workflow) {
return /^(schedule|workflow_dispatch|workflow_run)$/.test(workflow.event);
}
function read(url, callback) { function read(url, callback) {
var done = function(reply) { var done = function(reply) {
done = function() {}; done = function() {};
@@ -56,7 +60,7 @@ function read(url, callback) {
}).on("end", function() { }).on("end", function() {
var reply; var reply;
try { try {
reply = JSON.parse(chunks.join("")) reply = JSON.parse(chunks.join(""));
} catch (e) {} } catch (e) {}
done(reply); done(reply);
}).on("error", function() { }).on("error", function() {

View File

@@ -152,6 +152,7 @@ var SUPPORT = function(matrix) {
logical_assignment: "[].p ??= 0;", logical_assignment: "[].p ??= 0;",
new_target: "function f() { new.target; }", new_target: "function f() { new.target; }",
nullish: "0 ?? 0", nullish: "0 ?? 0",
optional_chaining: "0?.p",
rest: "var [...a] = [];", rest: "var [...a] = [];",
rest_object: "var {...a} = {};", rest_object: "var {...a} = {};",
spread: "[...[]];", spread: "[...[]];",
@@ -204,12 +205,20 @@ var VALUES = [
'"function"', '"function"',
"this", "this",
]; ];
VALUES = VALUES.concat(VALUES);
VALUES = VALUES.concat(VALUES);
VALUES = VALUES.concat(VALUES);
if (SUPPORT.bigint) VALUES = VALUES.concat([ if (SUPPORT.bigint) VALUES = VALUES.concat([
"(!0o644n)", "(!0o644n)",
"([3n][0] > 2)", "([3n][0] > 2)",
"(-42n).toString()", "(-42n).toString()",
"Number(0XDEADn << 16n | 0xbeefn)", "Number(0XDEADn << 16n | 0xbeefn)",
]); ]);
VALUES = VALUES.concat(VALUES);
VALUES = VALUES.concat(VALUES);
VALUES = VALUES.concat(VALUES);
VALUES = VALUES.concat(VALUES);
VALUES.push("import.meta");
var BINARY_OPS = [ var BINARY_OPS = [
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors) " + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
@@ -347,6 +356,7 @@ var block_vars = [];
var lambda_vars = []; var lambda_vars = [];
var unique_vars = []; var unique_vars = [];
var classes = []; var classes = [];
var allow_this = true;
var async = false; var async = false;
var has_await = false; var has_await = false;
var export_default = false; var export_default = false;
@@ -393,6 +403,7 @@ function createTopLevelCode() {
lambda_vars.length = 0; lambda_vars.length = 0;
unique_vars.length = 0; unique_vars.length = 0;
classes.length = 0; classes.length = 0;
allow_this = true;
async = false; async = false;
has_await = false; has_await = false;
export_default = false; export_default = false;
@@ -437,9 +448,9 @@ function addTrailingComma(list) {
function createParams(was_async, was_generator, noDuplicate) { function createParams(was_async, was_generator, noDuplicate) {
var save_async = async; var save_async = async;
if (was_async) async = true; if (!async) async = was_async;
var save_generator = generator; var save_generator = generator;
if (was_generator) generator = true; if (!generator) generator = was_generator;
var len = unique_vars.length; var len = unique_vars.length;
var params = []; var params = [];
for (var n = rng(4); --n >= 0;) { for (var n = rng(4); --n >= 0;) {
@@ -561,9 +572,9 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
function createName() { function createName() {
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity"); unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
var save_async = async; var save_async = async;
if (was_async) async = true; if (!async) async = was_async;
var save_generator = generator; var save_generator = generator;
if (was_generator) generator = true; if (!generator) generator = was_generator;
var name = createVarName(MANDATORY); var name = createVarName(MANDATORY);
generator = save_generator; generator = save_generator;
async = save_async; async = save_async;
@@ -974,8 +985,17 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
var label = createLabel(canBreak, canContinue); var label = createLabel(canBreak, canContinue);
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
var key = rng(10) ? "key" + loop : getVarName(NO_CONST);
var of = SUPPORT.for_of && rng(20) == 0; var of = SUPPORT.for_of && rng(20) == 0;
var key;
if (rng(10)) {
key = "key" + loop;
} else if (bug_for_of_async && of) {
addAvoidVar("async");
key = getVarName(NO_CONST);
removeAvoidVar("async");
} else {
key = getVarName(NO_CONST);
}
var init = ""; var init = "";
if (!/^key/.test(key)) { if (!/^key/.test(key)) {
if (!(of && bug_for_of_var) && rng(10) == 0) init = "var "; if (!(of && bug_for_of_var) && rng(10) == 0) init = "var ";
@@ -1171,7 +1191,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
var hadDefault = false; var hadDefault = false;
var s = [""]; var s = [ "" ];
canBreak = enableLoopControl(canBreak, CAN_BREAK); canBreak = enableLoopControl(canBreak, CAN_BREAK);
while (n-- > 0) { while (n-- > 0) {
//hadDefault = n > 0; // disables weird `default` clause positioning (use when handling destabilizes) //hadDefault = n > 0; // disables weird `default` clause positioning (use when handling destabilizes)
@@ -1470,12 +1490,16 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
return createValue() + " in " + createObjectLiteral(recurmax, stmtDepth, canThrow); return createValue() + " in " + createObjectLiteral(recurmax, stmtDepth, canThrow);
case p++: case p++:
var name = getVarName(); var name = getVarName();
var s = name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]"; var prop = "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]";
return canThrow && rng(20) == 0 ? s : name + " && " + s; if (SUPPORT.optional_chaining && rng(50) == 0) return name + "?." + prop;
if (canThrow && rng(20) == 0) return name + prop;
return name + " && " + name + prop;
case p++: case p++:
var name = getVarName(); var name = getVarName();
var s = name + "." + getDotKey(); var prop = getDotKey();
return canThrow && rng(20) == 0 ? s : name + " && " + s; if (SUPPORT.optional_chaining && rng(50) == 0) return name + "?." + prop;
if (canThrow && rng(20) == 0) return name + "." + prop;
return name + " && " + name + "." + prop;
case p++: case p++:
case p++: case p++:
var name = getVarName(); var name = getVarName();
@@ -1517,7 +1541,16 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2); name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
} while (name in called && !called[name]); } while (name in called && !called[name]);
called[name] = true; called[name] = true;
return mayDefer("typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + createArgs(recurmax, stmtDepth, canThrow)); var args = createArgs(recurmax, stmtDepth, canThrow);
var call = "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + args;
if (canThrow) {
if (SUPPORT.optional_chaining && args[0] != "`" && rng(50) == 0) {
call = "--_calls_ >= 0 && " + name + "?." + args;
} else if (rng(20) == 0) {
call = "--_calls_ >= 0 && " + name + args;
}
}
return mayDefer(call);
} }
_createExpression.N = p; _createExpression.N = p;
return _createExpression(recurmax, noComma, stmtDepth, canThrow); return _createExpression(recurmax, noComma, stmtDepth, canThrow);
@@ -1602,6 +1635,10 @@ var KEYS = [
"1.5", "1.5",
"3", "3",
].concat(SAFE_KEYS); ].concat(SAFE_KEYS);
SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS);
SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS);
SAFE_KEYS = SAFE_KEYS.concat(SAFE_KEYS);
SAFE_KEYS.push("__proto__");
function getDotKey(assign) { function getDotKey(assign) {
var key; var key;
@@ -1696,6 +1733,8 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
fn = function(defns) { fn = function(defns) {
if (generator) name = "*" + name; if (generator) name = "*" + name;
if (async) name = "async "+ name; if (async) name = "async "+ name;
var save_allow = allow_this;
if (internal == "super") allow_this = false;
s = [ s = [
name + "(" + createParams(save_async, save_generator, NO_DUPLICATE) + "){", name + "(" + createParams(save_async, save_generator, NO_DUPLICATE) + "){",
strictMode(), strictMode(),
@@ -1703,6 +1742,7 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
]; ];
s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth)); s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth));
if (internal == "super") s.push("super" + createArgs(recurmax, stmtDepth, canThrow, NO_TEMPLATE) + ";"); if (internal == "super") s.push("super" + createArgs(recurmax, stmtDepth, canThrow, NO_TEMPLATE) + ";");
allow_this = save_allow;
if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = rng(4); --i >= 0;) { if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = rng(4); --i >= 0;) {
s.push(rng(2) ? createSuperAssignment(recurmax, stmtDepth, canThrow) : createThisAssignment(recurmax, stmtDepth, canThrow)); s.push(rng(2) ? createSuperAssignment(recurmax, stmtDepth, canThrow) : createThisAssignment(recurmax, stmtDepth, canThrow));
} }
@@ -1719,8 +1759,9 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
function createObjectLiteral(recurmax, stmtDepth, canThrow) { function createObjectLiteral(recurmax, stmtDepth, canThrow) {
recurmax--; recurmax--;
var obj = ["({"]; var obj = [ "({" ];
var offset = SUPPORT.spread_object ? 0 : SUPPORT.computed_key ? 2 : 4; var offset = SUPPORT.spread_object ? 0 : SUPPORT.computed_key ? 2 : 4;
var has_proto = false;
for (var i = rng(6); --i >= 0;) switch (offset + rng(50 - offset)) { for (var i = rng(6); --i >= 0;) switch (offset + rng(50 - offset)) {
case 0: case 0:
obj.push("..." + getVarName() + ","); obj.push("..." + getVarName() + ",");
@@ -1736,7 +1777,12 @@ function createObjectLiteral(recurmax, stmtDepth, canThrow) {
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow) + ","); obj.push(createObjectFunction(recurmax, stmtDepth, canThrow) + ",");
break; break;
default: default:
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ": " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ","); if (has_proto || rng(200)) {
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ": " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ",");
} else {
obj.push("__proto__: " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " || {},");
has_proto = true;
}
break; break;
} }
obj.push("})"); obj.push("})");
@@ -1779,7 +1825,7 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
if (SUPPORT.class_field && rng(2)) { if (SUPPORT.class_field && rng(2)) {
s += internal || createObjectKey(recurmax, stmtDepth, canThrow); s += internal || createObjectKey(recurmax, stmtDepth, canThrow);
if (rng(5)) { if (rng(5)) {
async = false; async = bug_async_class_await && fixed && 0;
generator = false; generator = false;
s += " = " + createExpression(recurmax, NO_COMMA, stmtDepth, fixed ? canThrow : CANNOT_THROW); s += " = " + createExpression(recurmax, NO_COMMA, stmtDepth, fixed ? canThrow : CANNOT_THROW);
generator = save_generator; generator = save_generator;
@@ -1933,7 +1979,7 @@ function createValue() {
var v; var v;
do { do {
v = VALUES[rng(VALUES.length)]; v = VALUES[rng(VALUES.length)];
} while (v == "new.target" && rng(200)); } while (v == "new.target" && rng(200) || !allow_this && v == "this");
return v; return v;
} }
@@ -1983,7 +2029,7 @@ function isBannedKeyword(name) {
case "arguments": case "arguments":
return in_class; return in_class;
case "await": case "await":
return async; return async !== false;
case "yield": case "yield":
return generator || in_class; return generator || in_class;
} }
@@ -2028,6 +2074,7 @@ function createVarName(maybe, dontStore) {
if (require.main !== module) { if (require.main !== module) {
exports.createTopLevelCode = createTopLevelCode; exports.createTopLevelCode = createTopLevelCode;
exports.num_iterations = num_iterations; exports.num_iterations = num_iterations;
exports.verbose = verbose;
return; return;
} }
@@ -2256,7 +2303,7 @@ function is_error_in(ex) {
} }
function is_error_spread(ex) { function is_error_spread(ex) {
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| is not a function/.test(ex.message); return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function/.test(ex.message);
} }
function is_error_recursion(ex) { function is_error_recursion(ex) {
@@ -2375,6 +2422,8 @@ if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && typeof sandbox.run_code("a
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter"; return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
}; };
} }
var bug_async_class_await = SUPPORT.async && SUPPORT.class_field && typeof sandbox.run_code("var await; async function f() { class A { static p = await; } }") != "string";
var bug_for_of_async = SUPPORT.for_await_of && typeof sandbox.run_code("var async; for (async of []);") != "string";
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && typeof sandbox.run_code("try {} catch (e) { for (var e of []); }") != "string"; var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && typeof sandbox.run_code("try {} catch (e) { for (var e of []); }") != "string";
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") { if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
beautify_options.output.v8 = true; beautify_options.output.v8 = true;

View File

@@ -56,6 +56,9 @@ if (+process.env["UGLIFY_BUG_REPORT"]) exports.minify = function(files, options)
function describe_ast() { function describe_ast() {
var out = OutputStream({ beautify: true }); var out = OutputStream({ beautify: true });
doitem(AST_Node);
return out.get() + "\n";
function doitem(ctor) { function doitem(ctor) {
out.print("AST_" + ctor.TYPE); out.print("AST_" + ctor.TYPE);
var props = ctor.SELF_PROPS.filter(function(prop) { var props = ctor.SELF_PROPS.filter(function(prop) {
@@ -86,9 +89,7 @@ function describe_ast() {
}); });
}); });
} }
}; }
doitem(AST_Node);
return out + "\n";
} }
function infer_options(options) { function infer_options(options) {