Compare commits

...

88 Commits

Author SHA1 Message Date
Alex Lam S.L
787dfbed64
enhance inline (#5871) 2024-06-30 14:00:05 +03:00
Alex Lam S.L
6b23899ef3
fix corner case in collapse_vars (#5870)
fixes #5869
2024-06-28 21:19:58 +03:00
Alex Lam S.L
8c5a899986
enhance collapse_vars, unsafe & unused (#5868) 2024-06-26 22:38:27 +03:00
Alex Lam S.L
ed36c1ec5c
fix corner case in unused (#5867)
fixes #5866
2024-06-26 16:13:29 +03:00
Alex Lam S.L
ce8ef52e2b
enhance hoist_vars (#5865) 2024-06-25 23:56:39 +03:00
Alex Lam S.L
6669ea19ef
fix corner case in hoist_vars (#5864)
fixes #5863
2024-06-25 19:19:47 +03:00
Alex Lam S.L
205a1d1f19
fix corner case in reduce_vars (#5862)
fixes #5860
fixes #5861
2024-06-21 01:29:11 +03:00
Alex Lam S.L
95d3ede664
fix corner cases in pure_getters & reduce_vars (#5859)
fixes #5856
fixes #5857
fixes #5858
2024-06-20 17:43:55 +03:00
Alex Lam S.L
8195a664fd
fix corner case in collapse_vars (#5855)
fixes #5854
2024-06-19 05:15:03 +03:00
Alex Lam S.L
9c80456634
enhance dead_code & side_effects (#5840)
closes #5794
2024-06-19 01:36:04 +03:00
Alex Lam S.L
dc7aa32172
fix corner case in inline (#5853)
fixes #5851
2024-06-17 10:37:18 +03:00
Alex Lam S.L
23d74bedeb
fix corner cases in join_vars (#5852)
fixes #5849
fixes #5850
2024-06-17 09:11:11 +03:00
Alex Lam S.L
f31311e439
fix corner case in inline (#5848)
fixes #5844
2024-06-17 06:38:16 +03:00
Alex Lam S.L
87c9edbbc7
fix corner case in unused (#5847)
fixes #5843
2024-06-17 04:36:02 +03:00
Alex Lam S.L
8dc99fa25f
fix corner case in inline (#5846)
fixes #5842
2024-06-17 02:09:06 +03:00
Alex Lam S.L
dc51a23d31
fix corner case in inline (#5845)
fixes #5841
2024-06-17 02:08:53 +03:00
alexlamsl
0934c0e431 v3.18.0 2024-06-10 03:01:35 +03:00
Alex Lam S.L
ca4185a0fd
improve ESTree compatibility (#5836)
closes #5834
closes #5835
2024-06-10 01:37:24 +03:00
Alex Lam S.L
e7b9b4aafb
workaround function declaration quirks in ES6+ (#5833)
fixes #1666
2024-06-09 00:57:15 +03:00
Alex Lam S.L
3dfb379486
fix corner case in join_vars (#5832)
fixes #5831
2024-06-08 20:15:50 +03:00
Alex Lam S.L
2cb6454b1f
fix corner case in merge_vars (#5830)
fixes #5829
2024-06-08 20:15:37 +03:00
Alex Lam S.L
09910771a1
fix corner case in awaits (#5828)
fixes #5791
2024-06-06 04:51:02 +03:00
Alex Lam S.L
c21a8eee7b
include Node.js v20 in CI tests (#5827) 2024-06-05 23:49:20 +03:00
Alex Lam S.L
34b6143306
fix scope assignment to switch expressions (#5826)
fixes #5787
fixes #5792
2024-06-05 22:05:16 +03:00
Alex Lam S.L
ffe0fe7762
enhance join_vars (#5824)
closes #5790
2024-06-05 13:46:11 +03:00
forgotPassword
aa7c3389e6
domprops: enableHighAccuracy, maximumAge (#5822) 2024-06-05 04:17:30 +03:00
Alex Lam S.L
30fd331bf1
workaround node & npm issues (#5825)
- upgrade GitHub Actions dependencies
- workaround `sucrase` issues
2024-06-05 03:55:16 +03:00
Alex Lam S.L
f0ca9cfbe6
fix corner case in collapse_vars (#5780)
fixes #5779
2023-01-16 21:30:59 +08:00
Alex Lam S.L
a437a61518
fix corner case in reduce_vars (#5778)
fixes #5777
2023-01-16 21:30:45 +08:00
Alex Lam S.L
57dd3f6a2c
fix corner case in evaluate (#5775)
fixes #5774
2023-01-07 20:38:04 +08:00
Alex Lam S.L
f07dc5cfba
fix corner case in merge_vars (#5773)
fixes #5772
2023-01-07 18:27:18 +08:00
Alex Lam S.L
358faaacaa
fix corner case in merge_vars (#5771)
fixes #5770
2023-01-04 13:17:04 +08:00
Alex Lam S.L
c9117041fa
fix corner case in functions & inline (#5767)
fixes #5766
2022-12-27 08:59:16 +08:00
Alex Lam S.L
f2b6f1def0
improve --reduce-test (#5763) 2022-12-13 10:07:15 +08:00
Alex Lam S.L
797184f587
improve CLI interoperability (#5762) 2022-12-11 13:25:06 +08:00
Alex Lam S.L
78242ff21d
minor lints (#5761) 2022-12-09 05:55:57 +08:00
Alex Lam S.L
dd88f3866b
fix corner case in inline (#5760)
fixes #5759
2022-12-07 11:40:12 +08:00
Alex Lam S.L
17c3ae6cba
improve usability (#5758) 2022-12-04 09:10:32 +08:00
Alex Lam S.L
0cbd5ea64a
fix corner case in join_vars & loops (#5757)
fixes #5756
2022-12-03 11:44:37 +08:00
Alex Lam S.L
404794f5db
fix corner case in if_return (#5755)
fixes #5754
2022-12-02 11:05:36 +08:00
Alex Lam S.L
650e63c8aa
improve usability (#5753) 2022-12-02 10:14:07 +08:00
Alex Lam S.L
59e385591c
improve interoperability of custom Errors (#5752)
closes #5751
2022-12-02 03:54:00 +08:00
Alex Lam S.L
574ca47666
fix corner case in yields (#5750)
fixes #5749
2022-12-01 05:18:04 +08:00
Alex Lam S.L
548f0938e8
fix corner case in collapse_vars (#5748)
fixes #5747
2022-12-01 03:59:22 +08:00
Alex Lam S.L
2352909c3d
fix corner case in join_vars (#5746)
fixes #5745
2022-11-23 21:49:30 +08:00
Alex Lam S.L
4e7744af2d
minor lints (#5744) 2022-11-23 07:26:35 +08:00
Alex Lam S.L
aef7065262
fix corner case in inline (#5742)
fixes #5741
2022-11-23 07:26:08 +08:00
Alex Lam S.L
24c3db11e6
minor lints (#5740) 2022-11-23 05:08:42 +08:00
Alex Lam S.L
e5cbd3e0f3
enhance join_vars (#5739) 2022-11-23 01:57:16 +08:00
Alex Lam S.L
68d62a8a31
enable --module by default (#5738)
- fix corner case in `mangle`
2022-11-22 02:25:34 +08:00
Alex Lam S.L
21aff996a5
enhance varify (#5737) 2022-11-21 11:30:02 +08:00
Alex Lam S.L
1d400f1a25
fix corner case in inline (#5736)
fixes #5735
2022-11-14 10:35:26 +08:00
Alex Lam S.L
7f424a55c5
suppress false positives in ufuzz (#5734) 2022-11-14 10:34:43 +08:00
Alex Lam S.L
e37a1489d4
fix corner case in reduce_vars (#5731)
fixes #5730
2022-11-03 13:05:07 +08:00
Alex Lam S.L
2b1c321ac8
fix corner case in evaluate (#5729)
fixes #5728
2022-11-03 12:25:48 +08:00
Alex Lam S.L
8d28052182
fix corner cases in evaluate & side_effects (#5726) 2022-11-01 09:38:33 +08:00
Alex Lam S.L
f40dbd6e33
fix corner case in inline & unused (#5725)
fixes #5724
2022-10-29 10:53:30 +08:00
Alex Lam S.L
7270671687
fix corner case in conditionals (#5723)
fixes #5722
2022-10-29 00:17:59 +08:00
Alex Lam S.L
30bf068768
fix corner case in collapse_vars (#5720)
fixes #5719
2022-10-24 22:16:06 +08:00
Alex Lam S.L
fb1bff2c0a
v3.17.4 2022-10-24 01:46:19 +08:00
Alex Lam S.L
19c471c16a
fix corner cases in reduce_vars (#5717)
fixes #5716
2022-10-19 23:22:19 +08:00
Alex Lam S.L
8319badea8
fix corner case in merge_vars (#5715)
fixes #5714
2022-10-17 11:19:43 +08:00
Alex Lam S.L
5a5200d657
fix corner case in conditionals (#5713)
fixes #5712
2022-10-14 23:55:08 +08:00
Alex Lam S.L
5411360829
fix corner case in if_return (#5711)
fixes #5710
2022-10-13 22:34:55 +01:00
Alex Lam S.L
7edd10e5e5
fix corner case in unused (#5708)
fixes #5707
2022-10-10 21:45:57 +08:00
Alex Lam S.L
bccb1c3bd9
fix corner case in unused (#5706)
fixes #5705
2022-10-10 08:02:23 +08:00
Alex Lam S.L
ed7051b9bb
enhance side_effects & strings (#5704) 2022-10-10 08:01:40 +08:00
Alex Lam S.L
a391897388
enhance conditionals (#5703) 2022-10-08 09:59:33 +08:00
Alex Lam S.L
4a1da492dd
v3.17.3 2022-10-06 02:14:42 +08:00
Alex Lam S.L
94a954c3d1
minor clean-ups (#5701) 2022-10-06 02:06:21 +08:00
Alex Lam S.L
be8ccc3ab5
fix corner case in varify (#5698)
fixes #5697
2022-10-04 16:03:24 +08:00
Alex Lam S.L
58d997a3d6
fix corner case in booleans & conditionals (#5696) 2022-10-04 12:58:55 +08:00
Alex Lam S.L
dabcc39b51
fix corner cases in booleans & conditionals (#5695)
fixes #5694
2022-10-03 22:47:15 +08:00
Alex Lam S.L
140e4e0da8
fix corner case in inline (#5693)
fixes #5692
2022-10-03 08:01:56 +08:00
Alex Lam S.L
80fc862547
enhance assignments, booleans & conditionals (#5691) 2022-10-03 08:01:23 +08:00
Alex Lam S.L
6cdc035b2f
fix corner case in if_return (#5689)
fixes #5688
2022-09-30 06:49:51 +08:00
Alex Lam S.L
e1e3516397
fix corner case in reduce_vars (#5687) 2022-09-30 02:00:37 +08:00
Alex Lam S.L
bd5fc4cb1b
implement mangle.properties.domprops (#5686)
- support destructuring syntax
- fix corner case with comma operator
2022-09-29 12:18:04 +08:00
Alex Lam S.L
a570c00251
fix corner case in conditionals & if_return (#5685)
fixes #5684
2022-09-28 00:04:32 +08:00
Alex Lam S.L
3fa2086681
improve usability of mangle.properties (#5683)
fixes #5682
2022-09-27 13:52:58 +08:00
Alex Lam S.L
8e65413b99
fix corner cases in conditionals & if_return (#5680)
fixes #5679
2022-09-27 01:28:03 +08:00
Alex Lam S.L
8ca40070a4
workaround GitHub Actions quirks (#5678) 2022-09-27 00:16:40 +08:00
Alex Lam S.L
f9b811ce83
v3.17.2 2022-09-26 00:12:51 +08:00
Alex Lam S.L
9ac3879b06
fix corner case in conditionals (#5676) 2022-09-23 11:09:55 +08:00
Alex Lam S.L
37d3e4feaa
fix corner case in if_return (#5675) 2022-09-22 23:27:06 +08:00
Alex Lam S.L
43ec350cd2
fix corner case in conditionals (#5674)
fixes #5673
2022-09-22 10:58:44 +08:00
Alex Lam S.L
63b04a687a
minor tweaks (#5672) 2022-09-21 23:11:46 +08:00
Alex Lam S.L
9efa02afb6
fix corner case in assignments (#5671)
fixes #5670
2022-09-21 07:56:16 +08:00
87 changed files with 5901 additions and 731 deletions

View File

@ -9,11 +9,11 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
options: options:
- '-mb braces'
- '--ie -c' - '--ie -c'
- '-mc' - '-mb braces'
- '-p acorn --toplevel -mco spidermonkey' - '--toplevel -mc'
- '--toplevel -mc passes=3,pure_getters,unsafe' - '-p acorn -mco spidermonkey'
- '-mc passes=3,pure_getters,unsafe'
script: script:
- acorn.sh - acorn.sh
- bootstrap.sh - bootstrap.sh
@ -50,7 +50,7 @@ jobs:
OPTIONS: ${{ matrix.options }} OPTIONS: ${{ matrix.options }}
SCRIPT: ${{ matrix.script }} SCRIPT: ${{ matrix.script }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Perform uglify, build & test - name: Perform uglify, build & test
shell: bash shell: bash
run: | run: |

View File

@ -7,7 +7,7 @@ jobs:
test: test:
strategy: strategy:
matrix: matrix:
node: [ '0.10', '0.12', '4', '6', '8', '10', '12', '14', '16', latest ] node: [ '0.10', '0.12', '4', '6', '8', '10', '12', '14', '16', '18', '20' ]
os: [ ubuntu-latest, windows-latest ] os: [ ubuntu-latest, windows-latest ]
script: [ compress, mocha, release/benchmark, release/jetstream ] script: [ compress, mocha, release/benchmark, release/jetstream ]
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }} name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
@ -17,8 +17,8 @@ jobs:
TYPE: ${{ matrix.script }} TYPE: ${{ matrix.script }}
UGLIFY_GITHUB_LAG: 10000 UGLIFY_GITHUB_LAG: 10000
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v4
with: with:
path: tmp path: tmp
key: tmp ${{ matrix.script }} key: tmp ${{ matrix.script }}

18
.github/workflows/moz.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: ESTree
on:
pull_request:
push:
branches: [ master ]
jobs:
test:
name: fuzzing
runs-on: ubuntu-latest
env:
NODE: latest
steps:
- uses: actions/checkout@v4
- name: Perform tests
shell: bash
run: |
. ./test/release/install.sh
node test/mozilla-ast.js 5000

View File

@ -32,7 +32,7 @@ jobs:
env: env:
NODE: ${{ matrix.node }} NODE: ${{ matrix.node }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Perform fuzzing - name: Perform fuzzing
shell: bash shell: bash
run: | run: |

View File

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

View File

@ -1,6 +1,6 @@
UglifyJS is released under the BSD license: UglifyJS is released under the BSD license:
Copyright 2012-2019 (c) Mihai Bazon <mihai.bazon@gmail.com> Copyright 2012-2024 (c) Mihai Bazon <mihai.bazon@gmail.com>
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions

View File

@ -119,6 +119,8 @@ a double dash to prevent input files being used as option arguments:
--keep-fnames Do not mangle/drop function names. Useful for --keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name. code relying on Function.prototype.name.
--module Process input as ES module (implies --toplevel) --module Process input as ES module (implies --toplevel)
--no-module Avoid optimizations which may alter runtime behavior
under prior versions of JavaScript.
--name-cache <file> File to hold mangled name mappings. --name-cache <file> File to hold mangled name mappings.
--self Build UglifyJS as a library (implies --wrap UglifyJS) --self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options: --source-map [options] Enable source map/specify source map options:
@ -530,9 +532,9 @@ if (result.error) throw result.error;
- `mangle.properties` (default: `false`) — a subcategory of the mangle option. - `mangle.properties` (default: `false`) — a subcategory of the mangle option.
Pass an object to specify custom [mangle property options](#mangle-properties-options). Pass an object to specify custom [mangle property options](#mangle-properties-options).
- `module` (default: `false`) — set to `true` if you wish to process input as - `module` (default: `true`) — process input as ES module, i.e. implicit
ES module, i.e. implicit `"use strict";` and support for top-level `await`, `"use strict";` and support for top-level `await`. When explicitly specified,
alongside with `toplevel` enabled. also enables `toplevel`.
- `nameCache` (default: `null`) — pass an empty object `{}` or a previously - `nameCache` (default: `null`) — pass an empty object `{}` or a previously
used `nameCache` object if you wish to cache mangled variable and used `nameCache` object if you wish to cache mangled variable and
@ -646,7 +648,7 @@ to be `false` and all symbol names will be omitted.
- `bare_returns` (default: `false`) — support top level `return` statements - `bare_returns` (default: `false`) — support top level `return` statements
- `html5_comments` (default: `true`) — process HTML comment as workaround for - `html5_comments` (default: `true`) — process HTML comment as workaround for
browsers which do not recognise `<script>` tags browsers which do not recognize `<script>` tags
- `module` (default: `false`) — set to `true` if you wish to process input as - `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` and support for top-level `await`. ES module, i.e. implicit `"use strict";` and support for top-level `await`.
@ -750,10 +752,10 @@ to be `false` and all symbol names will be omitted.
- `merge_vars` (default: `true`) — combine and reuse variables. - `merge_vars` (default: `true`) — combine and reuse variables.
- `module` (default: `false`) — set to `true` if you wish to process input as - `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled. ES module, i.e. implicit `"use strict";`.
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions" - `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the where the return value is discarded, to avoid the parentheses that the
code generator would insert. code generator would insert.
- `objects` (default: `true`) — compact duplicate keys in object literals. - `objects` (default: `true`) — compact duplicate keys in object literals.
@ -777,11 +779,11 @@ to be `false` and all symbol names will be omitted.
overhead (compression will be slower). Make sure symbols under `pure_funcs` overhead (compression will be slower). Make sure symbols under `pure_funcs`
are also under `mangle.reserved` to avoid mangling. are also under `mangle.reserved` to avoid mangling.
- `pure_getters` (default: `"strict"`) — If you pass `true` for - `pure_getters` (default: `"strict"`) — Pass `true` for UglifyJS to assume that
this, UglifyJS will assume that object property access object property access (e.g. `foo.bar` or `a[42]`) does not throw exception or
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. alter program states via getter function. Pass `"strict"` to allow dropping or
Specify `"strict"` to treat `foo.bar` as side-effect-free only when reordering `foo.bar` only if `foo` is not `null` or `undefined` and is safe to
`foo` is certain to not throw, i.e. not `null` or `undefined`. access as a variable. Pass `false` to retain all property accesses.
- `reduce_funcs` (default: `true`) — Allows single-use functions to be - `reduce_funcs` (default: `true`) — Allows single-use functions to be
inlined as function expressions when permissible allowing further inlined as function expressions when permissible allowing further
@ -851,7 +853,7 @@ to be `false` and all symbol names will be omitted.
- `unused` (default: `true`) — drop unreferenced functions and variables (simple - `unused` (default: `true`) — drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`) direct variable assignments do not count as references unless set to `"keep_assign"`)
- `varify` (default: `true`) — convert block-scoped declaractions into `var` - `varify` (default: `true`) — convert block-scoped declarations into `var`
whenever safe to do so whenever safe to do so
- `yields` (default: `true`) — apply optimizations to `yield` expressions - `yields` (default: `true`) — apply optimizations to `yield` expressions
@ -891,12 +893,15 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
### Mangle properties options ### Mangle properties options
- `builtins` (default: `false`) — Use `true` to allow the mangling of builtin - `builtins` (default: `false`) — Use `true` to allow the mangling of built-in
DOM properties. Not recommended to override this setting. properties of JavaScript API. Not recommended to override this setting.
- `debug` (default: `false`) — Mangle names with the original name still present. - `debug` (default: `false`) — Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix. Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `domprops` (default: `false`) — Use `true` to allow the mangling of properties
commonly found in Document Object Model. Not recommended to override this setting.
- `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function - `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function
arguments. arguments.
@ -922,9 +927,8 @@ can pass additional arguments that control the code output:
regexps (affects directives with non-ascii characters becoming invalid) regexps (affects directives with non-ascii characters becoming invalid)
- `beautify` (default: `true`) — whether to actually beautify the output. - `beautify` (default: `true`) — whether to actually beautify the output.
Passing `-b` will set this to true, but you might need to pass `-b` even Passing `-b` will set this to true. Use `-O` if you want to generate minified
when you want to generate minified code, in order to specify additional code and specify additional arguments.
arguments, so you can use `-b beautify=false` to override it.
- `braces` (default: `false`) — always insert braces in `if`, `for`, - `braces` (default: `false`) — always insert braces in `if`, `for`,
`do`, `while` or `with` statements, even if their body is a single `do`, `while` or `with` statements, even if their body is a single

View File

@ -108,7 +108,8 @@ function process_option(name, no_value) {
" --ie Support non-standard Internet Explorer.", " --ie Support non-standard Internet Explorer.",
" --keep-fargs Do not mangle/drop function arguments.", " --keep-fargs Do not mangle/drop function arguments.",
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.", " --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
" --module Process input as ES module (implies --toplevel)", " --module Process input as ES module (implies --toplevel).",
" --no-module Process input with improved JavaScript compatibility.",
" --name-cache <file> File to hold mangled name mappings.", " --name-cache <file> File to hold mangled name mappings.",
" --rename Force symbol expansion.", " --rename Force symbol expansion.",
" --no-rename Disable symbol expansion.", " --no-rename Disable symbol expansion.",
@ -155,7 +156,6 @@ function process_option(name, no_value) {
case "expression": case "expression":
case "ie": case "ie":
case "ie8": case "ie8":
case "module":
case "timings": case "timings":
case "toplevel": case "toplevel":
case "v8": case "v8":
@ -201,6 +201,12 @@ function process_option(name, no_value) {
if (typeof options.mangle != "object") options.mangle = {}; if (typeof options.mangle != "object") options.mangle = {};
options.mangle.properties = parse_js(read_value(), options.mangle.properties); options.mangle.properties = parse_js(read_value(), options.mangle.properties);
break; break;
case "module":
options.module = true;
break;
case "no-module":
options.module = false;
break;
case "name-cache": case "name-cache":
nameCache = read_value(true); nameCache = read_value(true);
options.nameCache = JSON.parse(read_file(nameCache, "{}")); options.nameCache = JSON.parse(read_file(nameCache, "{}"));
@ -238,17 +244,6 @@ if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot
[ "compress", "mangle" ].forEach(function(name) { [ "compress", "mangle" ].forEach(function(name) {
if (!(name in options)) options[name] = false; if (!(name in options)) options[name] = false;
}); });
if (options.mangle && options.mangle.properties) {
if (options.mangle.properties.domprops) {
delete options.mangle.properties.domprops;
} else {
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS.push_uniq(options.mangle.properties.reserved, name);
});
}
}
if (/^ast|spidermonkey$/.test(output)) { if (/^ast|spidermonkey$/.test(output)) {
if (typeof options.output != "object") options.output = {}; if (typeof options.output != "object") options.output = {};
options.output.ast = true; options.output.ast = true;
@ -306,9 +301,19 @@ if (specified["in-situ"]) {
process.stdin.setEncoding("utf8"); process.stdin.setEncoding("utf8");
process.stdin.once("data", function() { process.stdin.once("data", function() {
clearTimeout(timerId); clearTimeout(timerId);
}).on("data", function(chunk) { }).on("data", process.stdin.isTTY ? function(chunk) {
// emulate console input termination via Ctrl+D / Ctrl+Z
var match = /[\x04\x1a]\r?\n?$/.exec(chunk);
if (match) {
chunks.push(chunk.slice(0, -match[0].length));
process.stdin.pause();
process.stdin.emit("end");
} else {
chunks.push(chunk);
}
} : function(chunk) {
chunks.push(chunk); chunks.push(chunk);
}).on("end", function() { }).once("end", function() {
files = { STDIN: chunks.join("") }; files = { STDIN: chunks.join("") };
run(); run();
}); });

View File

@ -169,8 +169,6 @@ DEF_BITPROPS(AST_Node, [
"private", "private",
// AST_Call // AST_Call
"pure", "pure",
// AST_Assign
"redundant",
// AST_Node // AST_Node
"single_use", "single_use",
// AST_ClassProperty // AST_ClassProperty
@ -332,7 +330,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", { var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", {
$documentation: "Base class for all statements introducing a lexical scope", $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 inner scopes",
functions: "[Dictionary/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: "[Dictionary/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",

File diff suppressed because it is too large Load Diff

View File

@ -82,14 +82,14 @@ function minify(files, options) {
keep_fargs: false, keep_fargs: false,
keep_fnames: false, keep_fnames: false,
mangle: {}, mangle: {},
module: false, module: undefined,
nameCache: null, nameCache: null,
output: {}, output: {},
parse: {}, parse: {},
rename: undefined, rename: undefined,
sourceMap: false, sourceMap: false,
timings: false, timings: false,
toplevel: !!(options && options["module"]), toplevel: options && !options["expression"] && options["module"] ? true : undefined,
v8: false, v8: false,
validate: false, validate: false,
warnings: false, warnings: false,
@ -104,8 +104,9 @@ function minify(files, options) {
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]); if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]);
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]); if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]);
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
if (options.module === undefined && !options.ie) options.module = true;
if (options.module) set_shorthand("module", options, [ "compress", "parse" ]); if (options.module) set_shorthand("module", options, [ "compress", "parse" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]); if (options.toplevel !== undefined) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]); if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);
var quoted_props; var quoted_props;

View File

@ -125,6 +125,16 @@
body: normalize_directives(from_moz(M.body).body), body: normalize_directives(from_moz(M.body).body),
}); });
}, },
CallExpression: function(M) {
return new AST_Call({
start: my_start_token(M),
end: my_end_token(M),
expression: from_moz(M.callee),
args: M.arguments.map(from_moz),
optional: M.optional,
pure: M.pure,
});
},
ClassDeclaration: function(M) { ClassDeclaration: function(M) {
return new AST_DefClass({ return new AST_DefClass({
start: my_start_token(M), start: my_start_token(M),
@ -458,7 +468,7 @@
end: my_end_token(M), end: my_end_token(M),
}; };
if (M.bigint) { if (M.bigint) {
args.value = M.bigint.toLowerCase() + "n"; args.value = M.bigint.toLowerCase();
return new AST_BigInt(args); return new AST_BigInt(args);
} }
var val = M.value; var val = M.value;
@ -631,7 +641,6 @@
map("AssignmentPattern", AST_DefaultValue, "left>name, right>value"); map("AssignmentPattern", AST_DefaultValue, "left>name, right>value");
map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
map("NewExpression", AST_New, "callee>expression, arguments@args, pure=pure"); map("NewExpression", AST_New, "callee>expression, arguments@args, pure=pure");
map("CallExpression", AST_Call, "callee>expression, arguments@args, optional=optional, pure=pure");
map("SequenceExpression", AST_Sequence, "expressions@expressions"); map("SequenceExpression", AST_Sequence, "expressions@expressions");
map("SpreadElement", AST_Spread, "argument>expression"); map("SpreadElement", AST_Spread, "argument>expression");
map("ObjectExpression", AST_Object, "properties@properties"); map("ObjectExpression", AST_Object, "properties@properties");
@ -668,6 +677,7 @@
type: "ArrowFunctionExpression", type: "ArrowFunctionExpression",
async: is_async(M), async: is_async(M),
params: params, params: params,
expression: !!M.value,
body: M.value ? to_moz(M.value) : to_moz_scope("BlockStatement", M), body: M.value ? to_moz(M.value) : to_moz_scope("BlockStatement", M),
}; };
return { return {
@ -680,6 +690,21 @@
}; };
}); });
def_to_moz(AST_Call, function To_Moz_CallExpression(M) {
var expr = M.expression;
if (M.args.length == 1 && expr instanceof AST_SymbolRef && expr.name == "import") return {
type: "ImportExpression",
source: to_moz(M.args[0]),
};
return {
type: "CallExpression",
callee: to_moz(expr),
arguments: M.args.map(to_moz),
optional: M.optional,
pure: M.pure,
};
});
def_to_moz(AST_DefClass, function To_Moz_ClassDeclaration(M) { def_to_moz(AST_DefClass, function To_Moz_ClassDeclaration(M) {
return { return {
type: "ClassDeclaration", type: "ClassDeclaration",
@ -767,6 +792,7 @@
def_to_moz(AST_Directive, function To_Moz_Directive(M) { def_to_moz(AST_Directive, function To_Moz_Directive(M) {
return { return {
type: "ExpressionStatement", type: "ExpressionStatement",
directive: M.value,
expression: set_moz_loc(M, { expression: set_moz_loc(M, {
type: "Literal", type: "Literal",
value: M.value, value: M.value,
@ -787,7 +813,6 @@
type: "TryStatement", type: "TryStatement",
block: to_moz_block(M), block: to_moz_block(M),
handler: to_moz(M.bcatch), handler: to_moz(M.bcatch),
guardedHandlers: [],
finalizer: to_moz(M.bfinally), finalizer: to_moz(M.bfinally),
}; };
}); });
@ -796,7 +821,6 @@
return { return {
type: "CatchClause", type: "CatchClause",
param: to_moz(M.argname), param: to_moz(M.argname),
guard: null,
body: to_moz_block(M), body: to_moz_block(M),
}; };
}); });
@ -805,6 +829,7 @@
return { return {
type: "ExportNamedDeclaration", type: "ExportNamedDeclaration",
declaration: to_moz(M.body), declaration: to_moz(M.body),
specifiers: [],
}; };
}); });
@ -954,6 +979,8 @@
type: "Property", type: "Property",
kind: "init", kind: "init",
computed: computed, computed: computed,
method: false,
shorthand: false,
key: key, key: key,
value: to_moz(M.value), value: to_moz(M.value),
}; };
@ -990,6 +1017,7 @@
kind: kind, kind: kind,
computed: computed, computed: computed,
method: M instanceof AST_ObjectMethod, method: M instanceof AST_ObjectMethod,
shorthand: false,
key: key, key: key,
value: to_moz(M.value), value: to_moz(M.value),
}; };
@ -1043,8 +1071,8 @@
var value = M.value; var value = M.value;
return { return {
type: "Literal", type: "Literal",
bigint: value.slice(0, -1), bigint: value,
raw: value, raw: value + "n",
}; };
}); });

View File

@ -76,7 +76,7 @@ function OutputStream(options) {
wrap_iife : false, wrap_iife : false,
}, true); }, true);
// Convert comment option to RegExp if neccessary and set up comments filter // Convert comment option to RegExp if necessary and set up comments filter
var comment_filter = return_false; // Default case, throw all comments away var comment_filter = return_false; // Default case, throw all comments away
if (options.comments) { if (options.comments) {
var comments = options.comments; var comments = options.comments;
@ -997,7 +997,7 @@ function OutputStream(options) {
if (self.init instanceof AST_Definitions) { if (self.init instanceof AST_Definitions) {
self.init.print(output); self.init.print(output);
} else { } else {
parenthesize_for_noin(self.init, output, true); parenthesize_for_no_in(self.init, output, true);
} }
output.print(";"); output.print(";");
output.space(); output.space();
@ -1413,7 +1413,7 @@ function OutputStream(options) {
print_braced(this, output); print_braced(this, output);
}); });
function print_definitinos(type) { function print_definitions(type) {
return function(output) { return function(output) {
var self = this; var self = this;
output.print(type); output.print(type);
@ -1426,15 +1426,15 @@ function OutputStream(options) {
if (!(p instanceof AST_IterationStatement && p.init === self)) output.semicolon(); if (!(p instanceof AST_IterationStatement && p.init === self)) output.semicolon();
}; };
} }
DEFPRINT(AST_Const, print_definitinos("const")); DEFPRINT(AST_Const, print_definitions("const"));
DEFPRINT(AST_Let, print_definitinos("let")); DEFPRINT(AST_Let, print_definitions("let"));
DEFPRINT(AST_Var, print_definitinos("var")); DEFPRINT(AST_Var, print_definitions("var"));
function parenthesize_for_noin(node, output, noin) { function parenthesize_for_no_in(node, output, no_in) {
var parens = false; var parens = false;
// need to take some precautions here: // need to take some precautions here:
// https://github.com/mishoo/UglifyJS/issues/60 // https://github.com/mishoo/UglifyJS/issues/60
if (noin) node.walk(new TreeWalker(function(node) { if (no_in) node.walk(new TreeWalker(function(node) {
if (parens) return true; if (parens) return true;
if (node instanceof AST_Binary && node.operator == "in") return parens = true; if (node instanceof AST_Binary && node.operator == "in") return parens = true;
if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true; if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true;
@ -1450,8 +1450,8 @@ function OutputStream(options) {
output.print("="); output.print("=");
output.space(); output.space();
var p = output.parent(1); var p = output.parent(1);
var noin = p instanceof AST_For || p instanceof AST_ForEnumeration; var no_in = p instanceof AST_For || p instanceof AST_ForEnumeration;
parenthesize_for_noin(self.value, output, noin); parenthesize_for_no_in(self.value, output, no_in);
} }
}); });
@ -1783,6 +1783,9 @@ function OutputStream(options) {
output.print(self.strings[i]); output.print(self.strings[i]);
output.print("`"); output.print("`");
}); });
DEFPRINT(AST_BigInt, function(output) {
output.print(this.value + "n");
});
DEFPRINT(AST_Constant, function(output) { DEFPRINT(AST_Constant, function(output) {
output.print("" + this.value); output.print("" + this.value);
}); });

View File

@ -207,11 +207,14 @@ function JS_Parse_Error(message, filename, line, col, pos) {
this.line = line; this.line = line;
this.col = col; this.col = col;
this.pos = pos; this.pos = pos;
try {
throw new SyntaxError(message, filename, line, col);
} catch (cause) {
configure_error_stack(this, cause);
}
} }
JS_Parse_Error.prototype = Object.create(Error.prototype); JS_Parse_Error.prototype = Object.create(SyntaxError.prototype);
JS_Parse_Error.prototype.constructor = JS_Parse_Error; JS_Parse_Error.prototype.constructor = JS_Parse_Error;
JS_Parse_Error.prototype.name = "SyntaxError";
configure_error_stack(JS_Parse_Error);
function js_error(message, filename, line, col, pos) { function js_error(message, filename, line, col, pos) {
throw new JS_Parse_Error(message, filename, line, col, pos); throw new JS_Parse_Error(message, filename, line, col, pos);
@ -391,7 +394,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var valid = parse_js_number(num); var valid = parse_js_number(num);
if (isNaN(valid)) parse_error("Invalid syntax: " + num); if (isNaN(valid)) parse_error("Invalid syntax: " + num);
if (has_dot || has_e || peek() != "n") return token("num", valid); if (has_dot || has_e || peek() != "n") return token("num", valid);
return token("bigint", num.toLowerCase() + next()); next();
return token("bigint", num.toLowerCase());
} }
function read_escaped_char(in_string) { function read_escaped_char(in_string) {
@ -782,7 +786,7 @@ function parse($TEXT, options) {
else if (!optional && !can_insert_semicolon()) expect(";"); else if (!optional && !can_insert_semicolon()) expect(";");
} }
function parenthesised() { function parenthesized() {
expect("("); expect("(");
var exp = expression(); var exp = expression();
expect(")"); expect(")");
@ -920,18 +924,18 @@ function parse($TEXT, options) {
next(); next();
var body = in_loop(statement); var body = in_loop(statement);
expect_token("keyword", "while"); expect_token("keyword", "while");
var condition = parenthesised(); var condition = parenthesized();
semicolon(true); semicolon(true);
return new AST_Do({ return new AST_Do({
body : body, body : body,
condition : condition condition : condition,
}); });
case "while": case "while":
next(); next();
return new AST_While({ return new AST_While({
condition : parenthesised(), condition : parenthesized(),
body : in_loop(statement) body : in_loop(statement),
}); });
case "for": case "for":
@ -959,15 +963,13 @@ function parse($TEXT, options) {
value = expression(); value = expression();
semicolon(); semicolon();
} }
return new AST_Return({ return new AST_Return({ value: value });
value: value
});
case "switch": case "switch":
next(); next();
return new AST_Switch({ return new AST_Switch({
expression : parenthesised(), expression : parenthesized(),
body : in_loop(switch_body_) body : in_loop(switch_body_),
}); });
case "throw": case "throw":
@ -976,9 +978,7 @@ function parse($TEXT, options) {
croak("Illegal newline after 'throw'"); croak("Illegal newline after 'throw'");
var value = expression(); var value = expression();
semicolon(); semicolon();
return new AST_Throw({ return new AST_Throw({ value: value });
value: value
});
case "try": case "try":
next(); next();
@ -996,8 +996,8 @@ function parse($TEXT, options) {
} }
next(); next();
return new AST_With({ return new AST_With({
expression : parenthesised(), expression : parenthesized(),
body : statement() body : statement(),
}); });
} }
} }
@ -1421,15 +1421,15 @@ function parse($TEXT, options) {
}; };
function if_() { function if_() {
var cond = parenthesised(), body = statement(), belse = null; var cond = parenthesized(), body = statement(), alt = null;
if (is("keyword", "else")) { if (is("keyword", "else")) {
next(); next();
belse = statement(); alt = statement();
} }
return new AST_If({ return new AST_If({
condition : cond, condition : cond,
body : body, body : body,
alternative : belse alternative : alt,
}); });
} }
@ -2171,9 +2171,9 @@ function parse($TEXT, options) {
token_error(sym.start, "Unexpected " + sym.name + " in strict mode"); token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
} }
function as_symbol(type, noerror) { function as_symbol(type, no_error) {
if (!is("name")) { if (!is("name")) {
if (!noerror) croak("Name expected"); if (!no_error) croak("Name expected");
return null; return null;
} }
var sym = _make_symbol(type, S.token); var sym = _make_symbol(type, S.token);
@ -2409,20 +2409,20 @@ function parse($TEXT, options) {
return new ctor({ operator: op, expression: expr }); return new ctor({ operator: op, expression: expr });
} }
var expr_op = function(left, min_prec, no_in) { var expr_op = function(left, min_precision, no_in) {
var op = is("operator") ? S.token.value : null; var op = is("operator") ? S.token.value : null;
if (op == "in" && no_in) op = null; if (op == "in" && no_in) op = null;
var prec = op != null ? PRECEDENCE[op] : null; var precision = op != null ? PRECEDENCE[op] : null;
if (prec != null && prec > min_prec) { if (precision != null && precision > min_precision) {
next(); next();
var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in); var right = expr_op(maybe_unary(no_in), op == "**" ? precision - 1 : precision, no_in);
return expr_op(new AST_Binary({ return expr_op(new AST_Binary({
start : left.start, start : left.start,
left : left, left : left,
operator : op, operator : op,
right : right, right : right,
end : right.end end : right.end,
}), min_prec, no_in); }), min_precision, no_in);
} }
return left; return left;
}; };

View File

@ -124,12 +124,16 @@ function get_builtins() {
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_ClassProperty) { if (node instanceof AST_ClassProperty
if (node.start && node.start.quote) add(node.key); || node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else if (node.start && node.start.quote) {
add(node.key);
}
} else if (node instanceof AST_Dot) { } else if (node instanceof AST_Dot) {
if (node.quoted) add(node.property); if (node.quoted) add(node.property);
} else if (node instanceof AST_ObjectProperty) {
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);
} }
@ -156,12 +160,16 @@ function mangle_properties(ast, options) {
builtins: false, builtins: false,
cache: null, cache: null,
debug: false, debug: false,
domprops: false,
keep_quoted: false, keep_quoted: false,
regex: null, regex: null,
reserved: null, reserved: null,
}, true); }, true);
var reserved = options.builtins ? new Dictionary() : get_builtins(); var reserved = options.builtins ? new Dictionary() : get_builtins();
if (!options.domprops && typeof domprops !== "undefined") domprops.forEach(function(name) {
reserved.set(name, true);
});
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) { if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
reserved.set(name, true); reserved.set(name, true);
}); });
@ -180,7 +188,7 @@ function mangle_properties(ast, options) {
var regex = options.regex; var regex = options.regex;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled). // note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' // note debug may be enabled as an empty string, which is falsy. Also treat passing 'true'
// the same as passing an empty string. // the same as passing an empty string.
var debug = options.debug !== false; var debug = options.debug !== false;
var debug_suffix; var debug_suffix;
@ -191,9 +199,7 @@ function mangle_properties(ast, options) {
// step 1: find candidates to mangle // step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node) { ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_Binary) { if (node.TYPE == "Call") {
if (node.operator == "in") addStrings(node.left, add);
} else if (node.TYPE == "Call") {
var exp = node.expression; var exp = node.expression;
if (exp instanceof AST_Dot) switch (exp.property) { if (exp instanceof AST_Dot) switch (exp.property) {
case "defineProperty": case "defineProperty":
@ -210,14 +216,18 @@ function mangle_properties(ast, options) {
addStrings(node.args[0], add); addStrings(node.args[0], add);
break; break;
} }
} else if (node instanceof AST_ClassProperty) { } else if (node instanceof AST_ClassProperty
if (typeof node.key == "string") add(node.key); || node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else {
add(node.key);
}
} else if (node instanceof AST_Dot) { } else if (node instanceof AST_Dot) {
add(node.property); if (is_lhs(node, this.parent())) add(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") add(node.key);
} else if (node instanceof AST_Sub) { } else if (node instanceof AST_Sub) {
addStrings(node.property, add); if (is_lhs(node, this.parent())) addStrings(node.property, add);
} }
})); }));
@ -242,12 +252,16 @@ function mangle_properties(ast, options) {
mangleStrings(node.args[0]); mangleStrings(node.args[0]);
break; break;
} }
} else if (node instanceof AST_ClassProperty) { } else if (node instanceof AST_ClassProperty
if (typeof node.key == "string") node.key = mangle(node.key); || node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
mangleStrings(node.key);
} else {
node.key = mangle(node.key);
}
} else if (node instanceof AST_Dot) { } else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_Sub) { } else if (node instanceof AST_Sub) {
if (!options.keep_quoted) mangleStrings(node.property); if (!options.keep_quoted) mangleStrings(node.property);
} }
@ -303,7 +317,7 @@ function mangle_properties(ast, options) {
function mangleStrings(node) { function mangleStrings(node) {
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {
mangleStrings(node.expressions.tail_node()); mangleStrings(node.tail_node());
} else if (node instanceof AST_String) { } else if (node instanceof AST_String) {
node.value = mangle(node.value); node.value = mangle(node.value);
} else if (node instanceof AST_Conditional) { } else if (node instanceof AST_Conditional) {

View File

@ -68,9 +68,7 @@ SymbolDef.prototype = {
var cache = this.global && options.cache && options.cache.props; var cache = this.global && options.cache && options.cache.props;
if (cache && cache.has(this.name)) { if (cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name); this.mangled_name = cache.get(this.name);
} else if (this.unmangleable(options)) { } else if (!this.unmangleable(options)) {
names_in_use(this.scope, options).set(this.name, true);
} else {
var def = this.redefined(); var def = this.redefined();
if (def) { if (def) {
this.mangled_name = def.mangled_name || def.name; this.mangled_name = def.mangled_name || def.name;
@ -180,6 +178,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}); });
return true; return true;
} }
if (node instanceof AST_Switch) {
node.expression.walk(tw);
walk_scope(function() {
walk_body(node, tw);
});
return true;
}
if (node instanceof AST_SwitchBranch) { if (node instanceof AST_SwitchBranch) {
node.init_vars(scope); node.init_vars(scope);
descend(); descend();
@ -439,35 +444,43 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
} }
}); });
function init_block_vars(scope, parent) { function init_block_vars(scope, parent, orig) {
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes // variables from this or outer scope(s) that are referenced from this or inner scopes
scope.parent_scope = parent; // the parent scope (null if this is the top level) scope.enclosed = orig ? orig.enclosed.slice() : [];
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) // map name to AST_SymbolDefun (functions defined in this scope)
scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) scope.functions = orig ? orig.functions.clone() : new Dictionary();
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances // map name to AST_SymbolVar (variables defined in this scope; includes functions)
scope.variables = orig ? orig.variables.clone() : new Dictionary();
if (!parent) return;
// top-level tracking of SymbolDef instances
scope.make_def = parent.make_def;
// the parent scope (null if this is the top level)
scope.parent_scope = parent;
} }
function init_scope_vars(scope, parent) { function init_scope_vars(scope, parent, orig) {
init_block_vars(scope, parent); init_block_vars(scope, parent, orig);
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` // will be set to true if this or nested scope uses the global `eval`
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement scope.uses_eval = false;
// will be set to true if this or some nested scope uses the `with` statement
scope.uses_with = false;
} }
AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) { AST_BlockScope.DEFMETHOD("init_vars", function(parent, orig) {
init_block_vars(this, parent_scope); init_block_vars(this, parent, orig);
}); });
AST_Scope.DEFMETHOD("init_vars", function(parent_scope) { AST_Scope.DEFMETHOD("init_vars", function(parent, orig) {
init_scope_vars(this, parent_scope); init_scope_vars(this, parent, orig);
}); });
AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) { AST_Arrow.DEFMETHOD("init_vars", function(parent, orig) {
init_scope_vars(this, parent_scope); init_scope_vars(this, parent, orig);
return this; return this;
}); });
AST_AsyncArrow.DEFMETHOD("init_vars", function(parent_scope) { AST_AsyncArrow.DEFMETHOD("init_vars", function(parent, orig) {
init_scope_vars(this, parent_scope); init_scope_vars(this, parent, orig);
}); });
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) { AST_Lambda.DEFMETHOD("init_vars", function(parent, orig) {
init_scope_vars(this, parent_scope); init_scope_vars(this, parent, orig);
this.uses_arguments = false; this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({ this.def_variable(new AST_SymbolFunarg({
name: "arguments", name: "arguments",
@ -643,8 +656,12 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
}, true); }, true);
} }
var to_mangle = node.to_mangle = []; var to_mangle = node.to_mangle = [];
node.variables.each(function(def) { node.variables.each(function(def, name) {
if (!defer_redef(def)) to_mangle.push(def); if (def.unmangleable(options)) {
names_in_use(node, options).set(name, true);
} else if (!defer_redef(def)) {
to_mangle.push(def);
}
}); });
descend(); descend();
if (options.cache && node instanceof AST_Toplevel) { if (options.cache && node instanceof AST_Toplevel) {

View File

@ -55,28 +55,41 @@ function find_if(func, array) {
for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i]; for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i];
} }
function configure_error_stack(fn) { function configure_error_stack(ex, cause) {
Object.defineProperty(fn.prototype, "stack", { var stack = ex.name + ": " + ex.message;
Object.defineProperty(ex, "stack", {
get: function() { get: function() {
var err = new Error(this.message); if (cause) {
err.name = this.name; cause.name = "" + ex.name;
try { stack = "" + cause.stack;
throw err; var msg = "" + cause.message;
} catch (e) { cause = null;
return e.stack; var index = stack.indexOf(msg);
if (index < 0) {
index = 0;
} else {
index += msg.length;
index = stack.indexOf("\n", index) + 1;
}
stack = stack.slice(0, index) + stack.slice(stack.indexOf("\n", index) + 1);
} }
} return stack;
},
}); });
} }
function DefaultsError(msg, defs) { function DefaultsError(msg, defs) {
this.message = msg; this.message = msg;
this.defs = defs; this.defs = defs;
try {
throw new Error(msg);
} catch (cause) {
configure_error_stack(this, cause);
}
} }
DefaultsError.prototype = Object.create(Error.prototype); DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError; DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError"; DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError);
function defaults(args, defs, croak) { function defaults(args, defs, croak) {
if (croak) for (var i in args) { if (croak) for (var i in args) {

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

View File

@ -3,6 +3,7 @@
"use strict"; "use strict";
require("../tools/tty");
var createHash = require("crypto").createHash; var createHash = require("crypto").createHash;
var fetch = require("./fetch"); var fetch = require("./fetch");
var spawn = require("child_process").spawn; var spawn = require("child_process").spawn;

View File

@ -126,6 +126,17 @@ function parse_test(file) {
croak(node); croak(node);
} }
var name = node.left.name; var name = node.left.name;
assert.ok([
"beautify",
"expression",
"mangle",
"options",
"rename",
].indexOf(name) >= 0, tmpl("Unsupported setting {name} [{line},{col}]", {
name: name,
line: node.start.line,
col: node.start.col,
}));
test[name] = evaluate(node.right); test[name] = evaluate(node.right);
return true; return true;
} }
@ -271,7 +282,9 @@ function test_case(test) {
expect = test.expect_exact; expect = test.expect_exact;
} }
var input = to_toplevel(test.input, test.mangle, test.expression); var input = to_toplevel(test.input, test.mangle, test.expression);
var input_code = make_code(input, {}, test.expression); var input_code = make_code(input, {
keep_quoted_props: true,
}, test.expression);
var input_formatted = make_code(test.input, { var input_formatted = make_code(test.input, {
annotations: true, annotations: true,
beautify: true, beautify: true,

View File

@ -690,6 +690,65 @@ inline_iife_within_arrow: {
node_version: ">=4" node_version: ">=4"
} }
instanceof_lambda_1: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(42 instanceof (() => {}));
}
expect: {
console.log(false);
}
expect_stdout: "false"
node_version: ">=4"
}
instanceof_lambda_2: {
options = {
evaluate: true,
side_effects: false,
}
input: {
console.log(null instanceof (() => {}));
}
expect: {
console.log((null, () => {}, false));
}
expect_stdout: "false"
node_version: ">=4"
}
instanceof_lambda_3: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log({} instanceof (() => {}));
}
expect: {
console.log({} instanceof (() => {}));
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=4"
}
instanceof_lambda_4: {
options = {
side_effects: true,
}
input: {
({ p: "foo" }) instanceof (() => {});
}
expect: {
[] instanceof (() => {});
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=4"
}
issue_4388: { issue_4388: {
options = { options = {
inline: true, inline: true,
@ -1253,7 +1312,7 @@ issue_5653: {
} }
expect: { expect: {
console.log((a => { console.log((a => {
return console, +{}; return +{};
})()); })());
} }
expect_stdout: "NaN" expect_stdout: "NaN"

View File

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

View File

@ -1348,7 +1348,7 @@ functions_inner_var: {
node_version: ">=8" node_version: ">=8"
} }
instanceof_lambda: { instanceof_lambda_1: {
options = { options = {
evaluate: true, evaluate: true,
side_effects: true, side_effects: true,
@ -1363,6 +1363,50 @@ instanceof_lambda: {
node_version: ">=8" node_version: ">=8"
} }
instanceof_lambda_2: {
options = {
evaluate: true,
side_effects: false,
}
input: {
console.log(null instanceof async function() {});
}
expect: {
console.log((null, async function() {}, false));
}
expect_stdout: "false"
node_version: ">=8"
}
instanceof_lambda_3: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log({} instanceof async function() {});
}
expect: {
console.log({} instanceof async function() {});
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=8"
}
instanceof_lambda_4: {
options = {
side_effects: true,
}
input: {
({ p: "foo" }) instanceof async function() {};
}
expect: {
[] instanceof async function() {};
}
expect_stdout: TypeError("Function has non-object prototype 'undefined' in instanceof check")
node_version: ">=8"
}
issue_4335_1: { issue_4335_1: {
options = { options = {
inline: true, inline: true,
@ -3540,3 +3584,124 @@ issue_5634_3_side_effects: {
] ]
node_version: ">=8" node_version: ">=8"
} }
issue_5692_1: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=10"
}
issue_5692_2: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
for (var k of []);
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}
issue_5791: {
options = {
awaits: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(async function() {
async function f() {
try {
await {
then(resolve) {
setImmediate(() => {
console.log("foo");
resolve();
});
},
};
} catch (e) {
console.log("FAIL", e);
}
}
async function g() {
try {
await f();
} catch (e) {}
}
await g();
console.log("bar");
})();
}
expect: {
(async function() {
await async function() {
try {
await async function() {
try {
await {
then(resolve) {
setImmediate(() => {
console.log("foo");
resolve();
});
},
};
} catch (e) {
console.log("FAIL", e);
}
}();
} catch (e) {}
}();
console.log("bar");
})();
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}

View File

@ -90,3 +90,17 @@ issue_4801: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=10.4.0" node_version: ">=10.4.0"
} }
issue_5728: {
options = {
evaluate: true,
}
input: {
console.log("" + 4n + 2);
}
expect: {
console.log("42");
}
expect_stdout: "42"
node_version: ">=10.4.0"
}

View File

@ -47,3 +47,45 @@ keep_some_blocks: {
} else stuff(); } else stuff();
} }
} }
issue_1666: {
input: {
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect: {
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect_stdout: true
}
issue_1666_strict: {
input: {
"use strict";
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect: {
"use strict";
var a = 42;
{
function a() {}
a();
}
console.log("PASS");
}
expect_stdout: true
}

View File

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

View File

@ -599,6 +599,7 @@ drop_extends: {
inline: true, inline: true,
passes: 2, passes: 2,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@ -921,6 +922,7 @@ single_use_3: {
single_use_4: { single_use_4: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@ -1163,9 +1165,9 @@ collapse_rhs_static: {
"use strict"; "use strict";
var a = "FAIL"; var a = "FAIL";
class A { class A {
static p = a = "PASS"; static p = "PASS";
} }
console.log(a); console.log(a = "PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=12" node_version: ">=12"
@ -1503,6 +1505,218 @@ keep_instanceof_3: {
node_version: ">=4" node_version: ">=4"
} }
keep_field_reference_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
class A {
p = f;
}
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f() {}
class A {
p = f;
}
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
var A = class {
p = f;
};
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f() {}
var A = class {
p = f;
};
console.log(new A().p === new A().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
class B {
p = A;
}
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
class A {}
class B {
p = A;
}
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_field_reference_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var A = class {};
var B = class {
p = A;
};
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect: {
"use strict";
var A = class {};
var B = class {
p = A;
};
console.log(new B().p === new B().p ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
class A {
static P = f;
}
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
class A {
static P = function() {};
}
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {}
var A = class {
static P = f;
};
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
var A = class {
static P = function() {};
};
console.log(A.P === A.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {}
class B {
static P = A;
}
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
class B {
static P = class {};
}
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
keep_static_field_reference_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var A = class {};
var B = class {
static P = A;
};
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect: {
"use strict";
var B = class {
static P = class {};
};
console.log(B.P === B.P ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=12"
}
issue_805_1: { issue_805_1: {
options = { options = {
inline: true, inline: true,
@ -2164,6 +2378,7 @@ issue_4829_2: {
mangle_properties: { mangle_properties: {
mangle = { mangle = {
properties: { properties: {
domprops: true,
keep_quoted: true, keep_quoted: true,
}, },
} }
@ -2202,11 +2417,11 @@ mangle_properties: {
expect_stdout: "PASS 42" expect_stdout: "PASS 42"
expect_warnings: [ expect_warnings: [
"INFO: Preserving reserved property q", "INFO: Preserving reserved property q",
"INFO: Preserving reserved property log",
"INFO: Mapping property #P to #t", "INFO: Mapping property #P to #t",
"INFO: Mapping property Q to s", "INFO: Mapping property Q to s",
"INFO: Mapping property #p to #i", "INFO: Mapping property #p to #i",
"INFO: Mapping property r to e", "INFO: Mapping property r to e",
"INFO: Preserving reserved property log",
] ]
node_version: ">=14.6" node_version: ">=14.6"
} }
@ -2312,6 +2527,7 @@ issue_4962_1: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2343,6 +2559,7 @@ issue_4962_1_strict: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2370,6 +2587,7 @@ issue_4962_1_strict_direct: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2401,6 +2619,7 @@ issue_4962_2: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2432,6 +2651,7 @@ issue_4962_2_strict: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2460,6 +2680,7 @@ issue_4962_2_strict_direct: {
options = { options = {
ie: true, ie: true,
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2494,6 +2715,7 @@ issue_4962_2_strict_direct_inline: {
ie: true, ie: true,
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2877,6 +3099,7 @@ issue_5053_4: {
issue_5082_1: { issue_5082_1: {
options = { options = {
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2909,6 +3132,7 @@ issue_5082_1: {
issue_5082_1_strict: { issue_5082_1_strict: {
options = { options = {
inline: true, inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2942,6 +3166,7 @@ issue_5082_2: {
options = { options = {
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -2975,6 +3200,7 @@ issue_5082_2_static: {
options = { options = {
inline: true, inline: true,
passes: 2, passes: 2,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@ -3619,3 +3845,188 @@ issue_5662: {
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
} }
issue_5682_class_key: {
mangle = {
properties: true,
}
input: {
"use strict";
function f(a) {
return "foo" in a;
}
class A {
foo() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f(o) {
return "o" in o;
}
class A {
o() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5682_class_key_computed: {
mangle = {
properties: true,
}
input: {
"use strict";
function f(a) {
return "foo" in a;
}
class A {
["foo"]() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect: {
"use strict";
function f(o) {
return "o" in o;
}
class A {
["o"]() {}
}
console.log(f(new A()) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5724: {
options = {
arrows: true,
inline: true,
keep_fargs: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
class A {
static P = function(a) {
console.log(a, a);
}(a);
}
}
expect: {
"use strict";
(function(a) {
console.log(a, a);
})(a);
}
expect_stdout: ReferenceError("a is not defined")
node_version: ">=12"
}
issue_5735_1: {
options = {
inline: true,
}
input: {
console.log(typeof function(a) {
return class {
static P = { ...a };
};
}([ 42..p ] = []));
}
expect: {
console.log(typeof function(a) {
return class {
static P = { ...a };
};
}([ 42..p ] = []));
}
expect_stdout: "function"
node_version: ">=12"
}
issue_5735_2: {
options = {
inline: true,
}
input: {
console.log(typeof function(a) {
return class {
p = a;
};
}(console.log("PASS")));
}
expect: {
console.log(typeof function(a) {
return class {
p = a;
};
}(console.log("PASS")));
}
expect_stdout: [
"PASS",
"function",
]
node_version: ">=12"
}
issue_5747_1: {
options = {
collapse_vars: true,
}
input: {
"use strict";
(async function() {
var a = await 42;
class A {
static P = a && console.log(typeof this);
}
})();
}
expect: {
"use strict";
(async function() {
var a = await 42;
class A {
static P = a && console.log(typeof this);
}
})();
}
expect_stdout: "function"
node_version: ">=12"
}
issue_5747_2: {
options = {
collapse_vars: true,
}
input: {
"use strict";
(async function() {
var a = await 42;
class A {
static {
a && console.log(typeof this);
}
}
})();
}
expect: {
"use strict";
(async function() {
var a = await 42;
class A {
static {
a && console.log(typeof this);
}
}
})();
}
expect_stdout: "function"
node_version: ">=16"
}

View File

@ -4996,7 +4996,7 @@ cascade_forin: {
] ]
} }
unsafe_builtin: { unsafe_builtin_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: "strict", pure_getters: "strict",
@ -5020,6 +5020,46 @@ unsafe_builtin: {
expect_stdout: "1 4" expect_stdout: "1 4"
} }
unsafe_builtin_2: {
options = {
collapse_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
A = "PASS";
var a = A;
console.log(a);
}
expect: {
console.log(A = "PASS");
}
expect_stdout: "PASS"
}
unsafe_builtin_3: {
options = {
collapse_vars: true,
unsafe: true,
unused: true,
}
input: {
A = "PASS";
(function() {
var a = A;
console.log(a);
})();
}
expect: {
A = "PASS";
(function() {
console.log(A);
})();
}
expect_stdout: "PASS"
}
return_1: { return_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@ -7350,30 +7390,39 @@ substitution_assign: {
b = 1 + (b = a); b = 1 + (b = a);
console.log(a, b); console.log(a, b);
} }
function f4(a, b) {
b = 1 + (a = b);
console.log(a, b);
}
f1(42, "foo"); f1(42, "foo");
f2(42, "foo"); f2(42, "foo");
f3(42, "foo"); f3(42, "foo");
f4("bar", 41);
} }
expect: { expect: {
function f1(a, b) { function f1(a, b) {
console.log(f1 = a, a); console.log(f1 = a, a);
} }
function f2(a, b) { function f2(a, b) {
a = 1 + (b = a); console.log(a = 1 + (b = a), b);
console.log(a, b);
} }
function f3(a, b) { function f3(a, b) {
b = 1 + (b = a); console.log(a, b = 1 + (b = a));
}
function f4(a, b) {
b = 1 + (a = b);
console.log(a, b); console.log(a, b);
} }
f1(42, "foo"); f1(42, "foo");
f2(42, "foo"); f2(42, "foo");
f3(42, "foo"); f3(42, "foo");
f4("bar", 41);
} }
expect_stdout: [ expect_stdout: [
"42 42", "42 42",
"43 42", "43 42",
"42 43", "42 43",
"41 42",
] ]
} }
@ -9864,7 +9913,8 @@ issue_5276: {
} }
expect: { expect: {
var a = A = "PASS"; var a = A = "PASS";
a.p = a.p + null - 42; a.p += null;
a.p -= 42;
console.log(a); console.log(a);
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@ -10121,3 +10171,189 @@ issue_5643: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_5719: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 42, b;
switch (b = a) {
case a:
case b:
case a++:
}
console.log(a === b++ ? "PASS" : "FAIL");
}
expect: {
var a = 42, b;
switch (b = a) {
case a:
case b:
case a++:
}
console.log(a === b++ ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_5779: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
}
input: {
var a = A = "foo";
a.p = 42;
if (a && !a.p)
console.log("PASS");
}
expect: {
var a = A = "foo";
a.p = 42;
if (a, !a.p)
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_1666: {
options = {
collapse_vars: true,
}
input: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}
issue_1666_strict: {
options = {
collapse_vars: true,
}
input: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}
issue_1666_undefined: {
options = {
collapse_vars: true,
}
input: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}
issue_1666_undefined_strict: {
options = {
collapse_vars: true,
}
input: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}
issue_5869: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a, b, log = console.log;
log();
a.p = 0;
b = a;
log(b);
}
expect: {
var a, log = console.log;
log();
log(void (a.p = 0));
}
expect_stdout: TypeError("Cannot set properties of undefined")
}

View File

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

View File

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

View File

@ -278,6 +278,36 @@ merge_tail_2: {
] ]
} }
merge_tail_3: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
if (b = a.shift())
console.log(b);
else {
if (b = a.shift())
while (console.log("foo"));
console.log(b);
}
})([ false, "bar" ]);
}
expect: {
(function(a, b) {
if (!(b = a.shift()) && (b = a.shift()))
while (console.log("foo"));
console.log(b);
})([ false, "bar" ]);
}
expect_stdout: [
"foo",
"bar",
]
}
merge_tail_sequence_1: { merge_tail_sequence_1: {
options = { options = {
conditionals: true, conditionals: true,
@ -368,6 +398,39 @@ merge_tail_sequence_2: {
] ]
} }
merge_tail_sequence_3: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
if (b = a.shift())
console.log("foo"),
console.log(b);
else {
if (b = a.shift())
while (console.log("bar"));
console.log(b);
}
})([ false, "baz" ]);
}
expect: {
(function(a, b) {
if (b = a.shift())
console.log("foo");
else if (b = a.shift())
while (console.log("bar"));
console.log(b);
})([ false, "baz" ]);
}
expect_stdout: [
"bar",
"baz",
]
}
cond_1: { cond_1: {
options = { options = {
conditionals: true, conditionals: true,
@ -2928,3 +2991,100 @@ issue_5666_2: {
} }
expect_stdout: "NaN" expect_stdout: "NaN"
} }
issue_5673_1: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b ? c : (c = a) && c);
}());
}
expect: {
var a = "PASS", b = null;
console.log(function(c) {
return c || (b || (c = a)) && c;
}());
}
expect_stdout: "PASS"
}
issue_5673_2: {
options = {
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
console.log(function(b) {
return (b = a) ? b : (b = a) && b;
}());
}
expect: {
var a = "PASS";
console.log(function(b) {
return a || (b = a) && b;
}());
}
expect_stdout: "PASS"
}
issue_5694: {
options = {
conditionals: true,
}
input: {
FORCE_EXEC = "async()=>{}";
var a = "foo";
// Node.js v0.12~6 (vm): foo
console.log((NaN = a) ? NaN : 42);
}
expect: {
FORCE_EXEC = "async()=>{}";
var a = "foo";
console.log((NaN = a) ? NaN : 42);
}
expect_stdout: "NaN"
}
issue_5712: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
}
input: {
var a = 0;
a || (++a).toString() && a && console.log("PASS");
}
expect: {
var a = 0;
a || (++a).toString() && a && console.log("PASS");
}
expect_stdout: "PASS"
}
issue_5722: {
options = {
conditionals: true,
evaluate: true,
keep_fnames: true,
side_effects: true,
}
input: {
var a = true;
a && function f() {
return 42;
}(a++) ? null + (console.log("PASS") && a++) : "";
}
expect: {
var a = true;
a && (void a++, console.log("PASS")) && a++;
}
expect_stdout: "PASS"
}

View File

@ -2204,3 +2204,30 @@ issue_5660: {
} }
expect_stdout: true expect_stdout: true
} }
issue_5787: {
options = {
unused: true,
}
input: {
console.log(function() {
const a = 42;
switch (a) {
case 42:
const a = "PASS";
return a;
}
}());
}
expect: {
console.log(function() {
const a = 42;
switch (a) {
case 42:
const a = "PASS";
return a;
}
}());
}
expect_stdout: true
}

View File

@ -2293,7 +2293,7 @@ issue_5340_3: {
} }
expect: { expect: {
var a; var a;
(function() {})(a = true["p"]); (function() {})(a = true.p);
console.log(a); console.log(a);
} }
expect_stdout: "undefined" expect_stdout: "undefined"
@ -3069,3 +3069,69 @@ issue_5651: {
expect_stdout: true expect_stdout: true
node_version: ">=6" node_version: ">=6"
} }
issue_5774: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
join_vars: true,
reduce_vars: true,
sequences: true,
unsafe: true,
}
input: {
(function() {
while (console.log("PASS")) {
if (console) {
a = void 0;
var b = void 0;
var c = void 0;
([ a = 0 ] = [ b, b ]);
var a;
}
}
})();
}
expect: {
(function() {
while (console.log("PASS")) {
var a, b, c, a;
console && (
c = b = a = void 0,
[ a = 0 ] = [ a, a ]
);
}
})();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5863: {
options = {
collapse_vars: true,
hoist_vars: true,
}
input: {
console.log(typeof function f(a = function() {
f = 42;
return f;
}()) {
var f;
var f;
return a;
}());
}
expect: {
console.log(typeof function f(a = function() {
f = 42;
return f;
}()) {
var f;
return a;
}());
}
expect_stdout: "function"
node_version: ">=6"
}

View File

@ -1339,7 +1339,7 @@ maintain_position_var: {
} }
expect: { expect: {
A = "FAIL"; A = "FAIL";
var [ , b ] = [ A ]; var b = [ A ][1];
console.log(b || "PASS"); console.log(b || "PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@ -1382,7 +1382,7 @@ side_effects_object: {
} }
} }
expect: { expect: {
var a = null, c = (console, 42["c"]); var a = null, c = (console, 42..c);
try { try {
c[a = "PASS"]; c[a = "PASS"];
} catch (e) { } catch (e) {
@ -1684,7 +1684,7 @@ singleton_1: {
expect: { expect: {
var b, a = "P"[0], o = {}; var b, a = "P"[0], o = {};
o.p = [ "FAIL"["1"] ][0]; o.p = [ "FAIL"["1"] ][0];
o.q = { foo: "S"[0] }["foo"]; o.q = { foo: "S"[0] }.foo;
[ b = "S" ] = []; [ b = "S" ] = [];
console.log(a + o.p + o.q + b); console.log(a + o.p + o.q + b);
} }
@ -1737,6 +1737,23 @@ singleton_side_effects: {
node_version: ">=6" node_version: ">=6"
} }
mangle_properties: {
mangle = {
properties: {
domprops: true,
},
}
input: {
function f({ p: a }) {
return a;
}
console.log(f({ p: "PASS" }));
}
expect_exact: 'function f({n}){return n}console.log(f({n:"PASS"}));'
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4280: { issue_4280: {
options = { options = {
evaluate: true, evaluate: true,
@ -3869,3 +3886,358 @@ issue_5651: {
expect_stdout: true expect_stdout: true
node_version: ">=6" node_version: ">=6"
} }
issue_5843_1: {
options = {
unused: true,
}
input: {
var { p: a } = {
__proto__: {
p: "PASS",
},
};
console.log(a);
}
expect: {
var a = {
__proto__: {
p: "PASS",
},
}.p;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5843_2: {
options = {
side_effects: true,
unused: true,
}
input: {
var a;
({ p: a } = {
__proto__: {
p: "PASS",
},
});
console.log(a);
}
expect: {
var a;
a = {
__proto__: {
p: "PASS",
},
}.p;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5844: {
options = {
inline: true,
}
input: {
try {
(function(a) {
[ a.p ] = 42;
})(console.log("PASS"));
} catch (e) {}
}
expect: {
try {
(function(a) {
[ a.p ] = 42;
})(console.log("PASS"));
} catch (e) {}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5854_1: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
var b = a;
a++;
[ b[0] ] = [ "foo" ];
return a;
}([]) ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
var b = a;
a++;
[ b[0] ] = [ "foo" ];
return a;
}([]) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5854_2: {
options = {
collapse_vars: true,
}
input: {
console.log(function(a) {
var b = a;
a++;
({ p: b[0] } = { p: "foo" });
return a;
}([]) ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
var b = a;
a++;
({ p: b[0] } = { p: "foo" });
return a;
}([]) ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_1: {
options = {
unused: true,
}
input: {
var a = {};
var { p: { q: b } } = {
p: a,
r: a.q = "PASS",
};
console.log(b);
}
expect: {
var a = {};
var { q: b } = {
p: a,
r: a.q = "PASS",
}.p;
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_2: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
({ p: { q: b } } = {
p: a,
r: a.q = "PASS",
});
console.log(b);
}
expect: {
var b, a = {};
({ q: b } = {
p: a,
r: a.q = "PASS",
}.p);
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_3: {
options = {
unused: true,
}
input: {
var a = {};
var [ { p: b } ] = [ a, a.p = "PASS" ];
console.log(b);
}
expect: {
var a = {};
var { p: b } = [ a, a.p = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_4: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
[ { p: b } ] = [ a, a.p = "PASS" ];
console.log(b);
}
expect: {
var b, a = {};
({ p: b } = [ a, a.p = "PASS" ][0]);
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_5: {
options = {
unused: true,
}
input: {
var a = [];
var [ [ b ] ] = [ a, a[0] = "PASS" ];
console.log(b);
}
expect: {
var a = [];
var [ b ] = [ a, a[0] = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_6: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = [], b;
[ [ b ] ] = [ a, a[0] = "PASS" ];
console.log(b);
}
expect: {
var b, a = [];
[ b ] = [ a, a[0] = "PASS" ][0];
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_7: {
options = {
unused: true,
}
input: {
var a = {};
var [ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var a = {};
var [ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_8: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b, c;
[ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var b, c, a = {};
[ { p: b }, c ] = [ a, a.p = {} ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_9: {
options = {
unused: true,
}
input: {
var a = {};
var [ b, { p: c } ] = [ a.p = {}, a ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var a = {};
var [ b, c ] = [ a.p = {}, a.p ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_10: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b, c;
[ b, { p: c } ] = [ a.p = {}, a ];
console.log(b === c ? "PASS" : "FAIL");
}
expect: {
var b, c, a = {};
[ b, c ] = [ a.p = {}, a.p ];
console.log(b === c ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_11: {
options = {
unused: true,
}
input: {
var a = {};
var { p: { q: b } } = { p: a = { q: {} } };
console.log(a.q === b ? "PASS" : "FAIL");
}
expect: {
var a = {};
var b = { p: (a = { q: {} }).q }.p;
console.log(a.q === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5866_12: {
options = {
side_effects: true,
unused: true,
}
input: {
var a = {}, b;
({ p: { q: b } } = { p: a = { q: {} } });
console.log(a.q === b ? "PASS" : "FAIL");
}
expect: {
var b, a = {};
b = { p: (a = { q: {} }).q }.p;
console.log(a.q === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@ -260,7 +260,7 @@ hoist_exports_2: {
} }
} }
expect: { expect: {
let e, a = 42["foo"]; let e, a = 42..foo;
function f(t, { [e]: o }) { function f(t, { [e]: o }) {
t(o, f); t(o, f);
} }

View File

@ -8663,6 +8663,7 @@ module_inline: {
inline: true, inline: true,
module: true, module: true,
reduce_vars: true, reduce_vars: true,
toplevel: true,
} }
input: { input: {
var a = f; var a = f;
@ -8719,3 +8720,254 @@ single_use_inline_collision: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5692: {
options = {
inline: true,
}
input: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect_stdout: "PASS"
}
issue_5766_1: {
options = {
booleans: true,
evaluate: true,
functions: true,
inline: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
log = function(a) {
console.log(typeof a);
};
do {
(function() {
try {
var f = function() {};
log(f && f);
} catch (e) {}
})();
} while (0);
}
expect: {
log = function(a) {
console.log(typeof a);
};
do {
try {
function f() {}
log(f);
} catch (e) {}
} while (0);
}
expect_stdout: "function"
}
issue_5766_2: {
options = {
evaluate: true,
functions: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
log = function(a) {
console.log(typeof a);
};
do {
(function() {
try {
var f = function() {};
log(f && f);
} catch (e) {}
})();
} while (0);
}
expect: {
log = function(a) {
console.log(typeof a);
};
do {
try {
function f() {}
log(f);
} catch (e) {}
} while (0);
}
expect_stdout: "function"
}
issue_5841_1: {
options = {
conditionals: true,
evaluate: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = 42;
(function() {
f();
var b = f();
function f() {
if (console && a)
g && g();
}
function g() {
var c;
for (;console.log("foo"););
(function h(d) {
d && d.p;
})();
}
})();
}
expect: {
var a = 42;
(function() {
f();
f();
function f() {
{
if (console && a) {
for (;console.log("foo"););
return;
}
return;
}
}
})();
}
expect_stdout: [
"foo",
"foo",
]
}
issue_5841_2: {
options = {
conditionals: true,
evaluate: true,
if_return: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = 42;
(function() {
f();
var b = f();
function f() {
if (console && a)
g && g();
}
function g() {
var c;
for (;console.log("foo"););
(function h(d) {
d && d.p;
})();
}
})();
}
expect: {
var a = 42;
(function() {
f();
f();
function f() {
if (console && a)
for (;console.log("foo"););
}
})();
}
expect_stdout: [
"foo",
"foo",
]
}
issue_5851_1: {
options = {
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
console.log("PASS") && f();
function f() {
return f();
}
f;
}
expect: {
console.log("PASS") && f();
function f() {
return f();
}
f;
}
expect_stdout: "PASS"
}
issue_5851_2: {
options = {
conditionals: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = f();
f();
function f() {
if (console.log("foo"))
console && f();
}
}
expect: {
f();
f();
function f() {
console.log("foo") && console && f();
}
}
expect_stdout: [
"foo",
"foo",
]
}

View File

@ -228,6 +228,7 @@ issue_4489: {
evaluate: true, evaluate: true,
hoist_vars: true, hoist_vars: true,
reduce_vars: true, reduce_vars: true,
sequences: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@ -363,6 +364,7 @@ issue_4893_1: {
evaluate: true, evaluate: true,
hoist_vars: true, hoist_vars: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@ -383,9 +385,8 @@ issue_4893_1: {
} }
expect: { expect: {
try{ try{
(function f() { (function() {
null.p += 42; null.p += 42;
f;
})(); })();
} catch (e) { } catch (e) {
console.log("PASS"); console.log("PASS");
@ -422,9 +423,7 @@ issue_4893_2: {
expect: { expect: {
try{ try{
(function() { (function() {
var a; null.p += 42;
a = null;
a.p += 42;
})(); })();
} catch (e) { } catch (e) {
console.log("PASS"); console.log("PASS");
@ -610,6 +609,7 @@ issue_5411_2: {
evaluate: true, evaluate: true,
hoist_vars: true, hoist_vars: true,
reduce_vars: true, reduce_vars: true,
sequences: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@ -622,9 +622,9 @@ issue_5411_2: {
} }
expect: { expect: {
var b, c; var b, c;
b++; b++,
b = "PASS", b = "PASS",
c; c,
console.log(b); console.log(b);
} }
expect_stdout: "PASS" expect_stdout: "PASS"

View File

@ -525,7 +525,7 @@ if_var_return_2: {
} }
} }
if_var_retrn_3: { if_var_return_3: {
options = { options = {
conditionals: true, conditionals: true,
if_return: true, if_return: true,
@ -1834,7 +1834,7 @@ switch_return_5: {
] ]
} }
merged_references: { merged_references_1: {
options = { options = {
if_return: true, if_return: true,
reduce_vars: true, reduce_vars: true,
@ -1861,6 +1861,36 @@ merged_references: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
merged_references_2: {
options = {
if_return: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
A = "PASS";
var a;
console.log(function(b) {
if (a = b)
return console && a;
a = FAIL;
return console && a;
}(A));
}
expect: {
A = "PASS";
var a;
console.log(function(b) {
if (a = b);
else
a = FAIL;
return console && a;
}(A));
}
expect_stdout: "PASS"
}
issue_5583: { issue_5583: {
options = { options = {
conditionals: true, conditionals: true,
@ -2412,3 +2442,41 @@ issue_5649: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5688: {
options = {
conditionals: true,
if_return: true,
}
input: {
L: do {
switch (console) {
default:
if (console)
break;
if (FAIL_1)
;
else
break L;
break;
case 42:
FAIL_2;
}
} while (console.log("PASS"));
}
expect: {
L: do {
switch (console) {
default:
if (console)
break;
if (FAIL_1)
break;
break L;
case 42:
FAIL_2;
}
} while (console.log("PASS"));
}
expect_stdout: "PASS"
}

View File

@ -140,12 +140,12 @@ mangle: {
} }
input: { input: {
import foo, { bar } from "baz"; import foo, { bar } from "baz";
consoe.log(moo); console.log(moo);
import * as moo from "moz"; import * as moo from "moz";
} }
expect: { expect: {
import o, { bar as m } from "baz"; import o, { bar as m } from "baz";
consoe.log(r); console.log(r);
import * as r from "moz"; import * as r from "moz";
} }
} }
@ -157,16 +157,44 @@ rename_mangle: {
} }
input: { input: {
import foo, { bar } from "baz"; import foo, { bar } from "baz";
consoe.log(moo); console.log(moo);
import * as moo from "moz"; import * as moo from "moz";
} }
expect: { expect: {
import o, { bar as m } from "baz"; import o, { bar as m } from "baz";
consoe.log(r); console.log(r);
import * as r from "moz"; import * as r from "moz";
} }
} }
mangle_export_import: {
mangle = {
toplevel: true,
}
input: {
export let o = A;
import { p as A } from "foo";
}
expect: {
export let o = p;
import { p } from "foo";
}
}
mangle_import_export: {
mangle = {
toplevel: true,
}
input: {
import { p as A } from "foo";
export let o = A;
}
expect: {
import { p } from "foo";
export let o = p;
}
}
keep_ref: { keep_ref: {
options = { options = {
reduce_vars: true, reduce_vars: true,

View File

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

View File

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

View File

@ -65,7 +65,9 @@ mangle_props: {
numeric_literal: { numeric_literal: {
mangle = { mangle = {
properties: true, properties: {
domprops: true,
},
} }
beautify = { beautify = {
beautify: true, beautify: true,
@ -115,9 +117,9 @@ numeric_literal: {
"8 7 8", "8 7 8",
] ]
expect_warnings: [ expect_warnings: [
"INFO: Preserving reserved property log",
"INFO: Mapping property 0x25 to o", "INFO: Mapping property 0x25 to o",
"INFO: Mapping property 1E42 to b", "INFO: Mapping property 1E42 to b",
"INFO: Preserving reserved property log",
] ]
} }
@ -125,6 +127,7 @@ identifier: {
mangle = { mangle = {
properties: { properties: {
builtins: true, builtins: true,
domprops: true,
}, },
} }
input: { input: {

View File

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

View File

@ -26,7 +26,7 @@ record_update: {
currying: { currying: {
options = { options = {
inline: true, inline: true,
passes: 2, passes: 3,
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,

View File

@ -1,6 +1,7 @@
dont_reuse_prop: { dont_reuse_prop: {
mangle = { mangle = {
properties: { properties: {
domprops: true,
regex: /asd/, regex: /asd/,
}, },
} }
@ -21,14 +22,15 @@ dont_reuse_prop: {
expect_stdout: "123" expect_stdout: "123"
expect_warnings: [ expect_warnings: [
"INFO: Preserving excluded property a", "INFO: Preserving excluded property a",
"INFO: Preserving reserved property log",
"INFO: Mapping property asd to b", "INFO: Mapping property asd to b",
"INFO: Preserving reserved property log",
] ]
} }
unmangleable_props_should_always_be_reserved: { unmangleable_props_should_always_be_reserved: {
mangle = { mangle = {
properties: { properties: {
domprops: true,
regex: /asd/, regex: /asd/,
}, },
} }
@ -49,7 +51,7 @@ unmangleable_props_should_always_be_reserved: {
expect_stdout: "123" expect_stdout: "123"
expect_warnings: [ expect_warnings: [
"INFO: Preserving excluded property a", "INFO: Preserving excluded property a",
"INFO: Preserving reserved property log",
"INFO: Mapping property asd to b", "INFO: Mapping property asd to b",
"INFO: Preserving reserved property log",
] ]
} }

View File

@ -16,6 +16,105 @@ join_vars_assign: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
join_array_assignments_1: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function () {
var a = [ "foo", , "bar" ];
a[1] = "baz";
a[7] = "moo";
a[0] = "moz";
return a;
}().join());
}
expect: {
console.log(function () {
var a = [ "moz", "baz", "bar", , , , , "moo" ];
return a;
}().join());
}
expect_stdout: "moz,baz,bar,,,,,moo"
}
join_array_assignments_2: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function () {
var a = [ "foo" ];
a[1] = "bar";
a[7] = "baz";
a[2] = "moo";
return a;
}().join());
}
expect: {
console.log(function () {
var a = [ "foo", "bar" ];
a[7] = "baz";
a[2] = "moo";
return a;
}().join());
}
expect_stdout: "foo,bar,moo,,,,,baz"
}
join_array_assignments_3: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function () {
var a = [ "foo" ];
a[1] = "bar";
a.b = "baz";
a[2] = "moo";
return a;
}().join());
}
expect: {
console.log(function () {
var a = [ "foo", "bar" ];
a.b = "baz";
a[2] = "moo";
return a;
}().join());
}
expect_stdout: true
}
join_array_assignments_4: {
options = {
evaluate: true,
join_vars: true,
side_effects: true,
}
input: {
console.log(function () {
var a = [ "foo" ];
a[0] = "bar";
a[1] = a;
a[2] = "baz";
return a;
}().join());
}
expect: {
console.log(function () {
var a = [ "bar" ];
a[1] = a;
a[2] = "baz";
return a;
}().join());
}
expect_stdout: true
}
join_object_assignments_1: { join_object_assignments_1: {
options = { options = {
evaluate: true, evaluate: true,
@ -570,7 +669,7 @@ inlined_assignments: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
inilne_for: { inline_for: {
options = { options = {
inline: true, inline: true,
join_vars: true, join_vars: true,
@ -590,7 +689,7 @@ inilne_for: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
inilne_var: { inline_var: {
options = { options = {
inline: true, inline: true,
join_vars: true, join_vars: true,
@ -1394,3 +1493,37 @@ issue_5175: {
} }
expect_stdout: "PASS PASS" expect_stdout: "PASS PASS"
} }
issue_5831: {
options = {
evaluate: true,
join_vars: true,
}
input: {
var a = [ console.log("PASS") ];
a[0] = 42;
}
expect: {
var a = [ (console.log("PASS"), 42) ];
}
expect_stdout: "PASS"
}
issue_5849: {
options = {
evaluate: true,
join_vars: true,
side_effects: true,
}
input: {
var a;
a = [ 42 ];
a[0] = "PASS";
console.log(a.join(""));
}
expect: {
var a, a = [ "PASS" ];
console.log(a.join(""));
}
expect_stdout: "PASS"
}

View File

@ -1130,6 +1130,130 @@ default_init: {
node_version: ">=4" node_version: ">=4"
} }
join_let_var_1: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
var a = "foo";
let b = "bar";
for (var c of [ a, b ])
console.log(c);
}
expect: {
"use strict";
let a = "foo", b = "bar";
for (var c of [ a, b ])
console.log(c);
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=4"
}
join_let_var_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
let a = "foo";
var b = "bar";
for (let c of [ a, b ])
console.log(c);
}
expect: {
"use strict";
let a = "foo", b = "bar";
for (let c of [ a, b ])
console.log(c);
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=4"
}
keep_let_var_1: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
var a = "foo";
let b = "bar";
for (var c of [ a, b ])
console.log(c);
function f() {
return a;
}
console.log(f(f));
}
expect: {
"use strict";
var a = "foo", c;
let b = "bar";
for (c of [ a, b ])
console.log(c);
function f() {
return a;
}
console.log(f(f));
}
expect_stdout: [
"foo",
"bar",
"foo",
]
node_version: ">=4"
}
keep_let_var_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
let a = "foo";
var b = "bar";
for (let c of [ a, b ])
console.log(c);
function f() {
return b;
}
console.log(f(f));
}
expect: {
"use strict";
let a = "foo";
var b = "bar";
for (let c of [ a, b ])
console.log(c);
function f() {
return b;
}
console.log(f(f));
}
expect_stdout: [
"foo",
"bar",
"bar",
]
node_version: ">=4"
}
issue_4191: { issue_4191: {
options = { options = {
functions: true, functions: true,
@ -2170,3 +2294,275 @@ issue_5591: {
] ]
node_version: ">=4" node_version: ">=4"
} }
issue_5741: {
options = {
inline: true,
join_vars: true,
reduce_vars: true,
}
input: {
"use strict";
(function(a) {
let b = function() {
var c = a;
console.log(c);
}();
function g() {
a++;
b;
}
})("PASS");
}
expect: {
"use strict";
(function(a) {
let b = (c = a, void console.log(c));
var c;
function g() {
a++;
b;
}
})("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5745_1: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
{
let f = function() {
return f && "PASS";
};
var a = f();
}
a;
console.log(a);
}
expect: {
"use strict";
{
let f = function() {
return f && "PASS";
};
var a = f();
}
a;
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5745_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
{
let f = function() {
return f && "PASS";
};
var a = f();
a;
console.log(a);
}
}
expect: {
"use strict";
{
let f = function() {
return f && "PASS";
}, a = f();
a;
console.log(a);
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5756_1: {
options = {
join_vars: true,
loops: true,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
do {
function f() {
return b;
}
var a = "PASS".toString();
let b;
console.log(a);
} while (!console);
}
expect: {
"use strict";
do {
function f() {
return b;
}
let a = "PASS".toString(), b;
console.log(a);
} while (!console);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5756_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {
let a = console.log("PASS");
{
var b;
for (var c in b) {
b;
var c = function() {
a;
};
}
}
}
f();
}
expect: {
"use strict";
(function() {
let a = console.log("PASS"), b;
for (c in b) {
b;
var c = function() {
a;
};
}
})();
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5756_3: {
options = {
module: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
"use strict";
console.log(f()());
function f() {
const a = "PASS";
return function() {
return a;
};
}
}
expect: {
"use strict";
console.log(function() {
let a = "PASS";
return function() {
return a;
};
}()());
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5759: {
options = {
collapse_vars: true,
inline: true,
join_vars: true,
reduce_vars: true,
unused: true,
}
input: {
"use strict";
function f() {
for (var a in [ true ]) {
let b;
(function() {
var c = void 0;
b;
console.log(c);
var d = null;
console.log(c);
})();
}
}
f();
}
expect: {
"use strict";
function f() {
for (var a in [ true ]) {
let b;
var c = c = void 0;
b;
console.log(c);
console.log(c);
}
}
f();
}
expect_stdout: [
"undefined",
"undefined",
]
node_version: ">=4"
}
issue_5787: {
options = {
unused: true,
}
input: {
console.log(function() {
let a = 42;
switch (a) {
case 42:
// Node.js v4 (vm): SyntaxError: Identifier 'a' has already been declared
let a = "PASS";
return a;
}
}());
}
expect: {
console.log(function() {
let a = 42;
switch (a) {
case 42:
let a = "PASS";
return a;
}
}());
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@ -3845,3 +3845,158 @@ issue_5471_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5714: {
options = {
inline: true,
join_vars: true,
loops: true,
merge_vars: true,
unused: true,
}
input: {
"use strict";
console.log(function() {
var i = 1;
while (i--) {
var a = function f(b) {
console.log(b);
var c = function(d) {
console.log(typeof d);
}(console);
}();
var e = 42;
}
return e;
}());
}
expect: {
"use strict";
console.log(function() {
for (var i = 1; i--;) {
var b = void 0;
console.log(b);
b = console,
console.log(typeof b);
var e = 42;
}
return e;
}());
}
expect_stdout: [
"undefined",
"object",
"42",
]
}
issue_5770_1: {
options = {
dead_code: true,
loops: true,
merge_vars: true,
toplevel: true,
}
input: {
L: do {
if (console)
for (var a = "FAIL 1"; a; a--)
continue L;
var b = "FAIL 2";
} while (console.log(b || "PASS"));
}
expect: {
L: do {
if (console) {
var a = "FAIL 1";
if (a)
continue L;
}
var b = "FAIL 2";
} while (console.log(b || "PASS"));
}
expect_stdout: "PASS"
}
issue_5770_2: {
options = {
conditionals: true,
dead_code: true,
if_return: true,
loops: true,
merge_vars: true,
toplevel: true,
}
input: {
L: do {
for (var a = "FAIL 1"; a; a--)
continue L;
var b = "FAIL 2";
} while (console.log(b || "PASS"));
}
expect: {
L: do {
var a = "FAIL 1";
var b;
} while (a || (b = "FAIL 2"), console.log(b || "PASS"));
}
expect_stdout: "PASS"
}
issue_5772_1: {
options = {
dead_code: true,
merge_vars: true,
loops: true,
}
input: {
(function(a) {
while (--a)
return;
var b = console.log("foo") && (c = 42) ? 0 : console.log(c);
var c = b;
})();
}
expect: {
(function(a) {
if (--a)
return;
var a = console.log("foo") && (c = 42) ? 0 : console.log(c);
var c = a;
})();
}
expect_stdout: [
"foo",
"undefined",
]
}
issue_5772_2: {
options = {
dead_code: true,
merge_vars: true,
loops: true,
}
input: {
(function(a) {
while (--a)
return;
var b;
var c = console.log("foo") && (b = 1) ? 2 : 3;
console.log(b, c);
})();
}
expect: {
(function(a) {
if (--a)
return;
var b;
var a = console.log("foo") && (b = 1) ? 2 : 3;
console.log(b, a);
})();
}
expect_stdout: [
"foo",
"undefined 3",
]
}

View File

@ -344,3 +344,43 @@ issue_5266: {
] ]
node_version: ">=14" node_version: ">=14"
} }
issue_5829_1: {
options = {
merge_vars: true,
}
input: {
(function f(a) {
var b;
(!a ?? (b = 0)) || console.log(b || "PASS");
})("FAIL");
}
expect: {
(function f(a) {
var b;
(!a ?? (b = 0)) || console.log(b || "PASS");
})("FAIL");
}
expect_stdout: "PASS"
node_version: ">=14"
}
issue_5829_2: {
options = {
merge_vars: true,
}
input: {
(function f(a) {
var b;
(a ?? (b = 0)) && console.log(b || "PASS");
})("FAIL");
}
expect: {
(function f(a) {
var b;
(a ?? (b = 0)) && console.log(b || "PASS");
})("FAIL");
}
expect_stdout: "PASS"
node_version: ">=14"
}

View File

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

View File

@ -617,3 +617,33 @@ issue_5292_sub_pure_getters_strict: {
] ]
node_version: ">=14" node_version: ">=14"
} }
issue_5856: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
try {
var a;
a?.p;
a.q;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
var a;
a?.p;
a.q;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=14"
}

View File

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

View File

@ -147,7 +147,7 @@ relational: {
"bar" >= "bar"; "bar" >= "bar";
} }
expect: { expect: {
0 instanceof bar(); [] instanceof bar();
bar(); bar();
bar(), bar(); bar(), bar();
bar(); bar();

View File

@ -1687,3 +1687,31 @@ issue_4939: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5856: {
options = {
pure_getters: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = [ "FAIL", "PASS" ];
(function(b) {
var c = b[0];
b[0] = b[1];
b[1] = c;
})(a);
console.log(a[0]);
}
expect: {
var a = [ "FAIL", "PASS" ];
(function(b) {
var c = b[0];
b[0] = b[1];
b[1] = c;
})(a);
console.log(a[0]);
}
expect_stdout: "PASS"
}

View File

@ -7927,3 +7927,422 @@ issue_5623: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_5716_1: {
options = {
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return b++ + (a = b);
}();
}
f();
console.log(a);
}
expect: {
c = [ c, c ],
void (c = ++c);
var c;
console.log(c);
}
expect_stdout: "NaN"
}
issue_5716_2: {
options = {
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b += 4) + (a = b += 2);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = (c = [ c, c ]) + 4 + 2);
var c;
console.log(c);
}
expect_stdout: ",42"
}
issue_5716_3: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b = b + 4) + (a = b += 2);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = (c = [ c, c ]) + 4 + 2);
var c;
console.log(c);
}
expect_stdout: ",42"
}
issue_5716_4: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
function f() {
var b = [ c, c ], c = function() {
return (b = true | b) + (a = b *= 42);
}();
}
f();
console.log(a);
}
expect: {
void (c = c = ((c = [ c, c ]) | true) * 42);
var c;
console.log(c);
}
expect_stdout: "42"
}
issue_5716_5: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(function() {
return 0 || (a = 42 | a);
var a = function() {
return a;
};
}());
}
expect: {
console.log(function() {
return 0 || (a |= 42);
var a = function() {
return a;
};
}());
}
expect_stdout: "42"
}
issue_5730_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
L: {
var f = function() {
console.log(a);
};
}
f();
a++;
}
expect: {
var a = "PASS";
var f = function() {
console.log(a);
};
f();
a++;
}
expect_stdout: "PASS"
}
issue_5730_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
try {
var f = function() {
console.log(a);
};
} finally {}
f();
a++;
}
expect: {
var a = "PASS";
try {
var f = function() {
console.log(a);
};
} finally {}
f();
a++;
}
expect_stdout: "PASS"
}
issue_5730_3: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var f, a = "PASS";
L: {
f = function() {
console.log(a);
};
}
f();
a++;
}
expect: {
var f, a = "PASS";
f = function() {
console.log(a);
};
f();
a++;
}
expect_stdout: "PASS"
}
issue_5777_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f() {
(function(a) {
function g() {
h();
}
g();
a = function() {};
function h() {
console.log(a);
}
})("PASS");
}
f();
}
expect: {
function f() {
(function(a) {
(function() {
h();
})();
a = function() {};
function h() {
console.log(a);
}
})("PASS");
}
f();
}
expect_stdout: "PASS"
}
issue_5777_2: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a) {
(function() {
function g() {
h();
}
g();
a = function() {};
function h() {
console.log(a);
}
})();
}
f("PASS");
}
expect: {
(function(a) {
(function() {
(function() {
h();
})();
a = function() {};
function h() {
console.log(a);
}
})();
})("PASS");
}
expect_stdout: "PASS"
}
issue_1666: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}
issue_1666_strict: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect: {
"use strict";
var x = 42;
{
x();
function x() {
console.log("foo");
}
}
console.log(typeof x);
}
expect_stdout: true
}
issue_1666_undefined: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}
issue_1666_undefined_strict: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect: {
"use strict";
var undefined = 42;
{
undefined();
function undefined() {
console.log("foo");
}
}
console.log(typeof undefined);
}
expect_stdout: true
}

View File

@ -739,3 +739,55 @@ issue_3480_ie8_toplevel: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_5787_1: {
rename = true
input: {
console.log(function() {
const a = 42;
switch (a) {
case 42:
const a = "PASS";
return a;
}
}());
}
expect: {
console.log(function() {
const a = 42;
switch (a) {
case 42:
const a = "PASS";
return a;
}
}());
}
expect_stdout: true
}
issue_5787_2: {
rename = true
input: {
console.log(function() {
let a = 42;
switch (a) {
case 42:
// Node.js v4 (vm): SyntaxError: Identifier 'a' has already been declared
let a = "PASS";
return a;
}
}());
}
expect: {
console.log(function() {
let a = 42;
switch (a) {
case 42:
let b = "PASS";
return b;
}
}());
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

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

View File

@ -125,6 +125,7 @@ log_nested: {
timers: { timers: {
options = { options = {
evaluate: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@ -132,26 +133,22 @@ timers: {
input: { input: {
var count = 0, interval = 1000, duration = 3210; var count = 0, interval = 1000, duration = 3210;
var timer = setInterval(function() { var timer = setInterval(function() {
console.log(++count); if (!count++) setTimeout(function() {
clearInterval(timer);
console.log(count <= 4 ? "PASS" : "FAIL");
}, duration);
}, interval); }, interval);
setTimeout(function() {
clearInterval(timer);
}, duration);
} }
expect: { expect: {
var count = 0; var count = 0;
var timer = setInterval(function() { var timer = setInterval(function() {
console.log(++count); if (!count++) setTimeout(function() {
clearInterval(timer);
console.log(count <= 4 ? "PASS" : "FAIL");
}, 3210);
}, 1000); }, 1000);
setTimeout(function() {
clearInterval(timer);
}, 3210);
} }
expect_stdout: [ expect_stdout: "PASS"
"1",
"2",
"3",
]
node_version: ">=0.12" node_version: ">=0.12"
} }

View File

@ -724,3 +724,246 @@ retain_instanceof: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
drop_access: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
try {
(function() {
o.q;
})();
console.log("PASS");
} catch (e) {
console.log("FAIL");
}
}
expect: {
var o = {};
o.p;
try {
console.log("PASS");
} catch (e) {
console.log("FAIL");
}
}
expect_stdout: "PASS"
}
keep_access: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
o = null;
try {
(function() {
o.q;
})();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var o = {};
o.p;
o = null;
try {
(function() {
o.q;
})();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
keep_access_after_call: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var o = {};
o.p;
o.q;
f();
try {
o.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
function f() {
o = null;
}
}
expect: {
var o = {};
o.p;
f();
try {
o.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
function f() {
o = null;
}
}
expect_stdout: "PASS"
}
issue_5860_drop_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
var a;
a.q;
console.log("PASS");
}
expect: {
var a = {};
a.p;
var a;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_5860_drop_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
a = {};
a.p;
var a;
a.q;
console.log("PASS");
}
expect: {
a = {};
a.p;
var a;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_5860_keep_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
a.q;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var a = {};
a.p;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_5860_keep_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
a = {};
a.p;
a.q;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
a = {};
a.p;
var a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_5860_keep_3: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
}
input: {
var a = {};
a.p;
a.q;
a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
var a = {};
a.p;
a = null;
try {
a.r;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}

View File

@ -13,12 +13,12 @@ collapse_vars_1: {
} }
input: { input: {
var a; var a;
[ ...a = "PASS", "PASS"].slice(); [ ...a = "PASS", "PASS" ].slice();
console.log(a); console.log(a);
} }
expect: { expect: {
var a; var a;
[ ...a = "PASS", "PASS"].slice(); [ ...a = "PASS", "PASS" ].slice();
console.log(a); console.log(a);
} }
expect_stdout: "PASS" expect_stdout: "PASS"
@ -33,7 +33,7 @@ collapse_vars_2: {
var a = "FAIL"; var a = "FAIL";
try { try {
a = "PASS"; a = "PASS";
[ ...42, "PASS"].slice(); [ ...42, "PASS" ].slice();
} catch (e) { } catch (e) {
console.log(a); console.log(a);
} }
@ -42,7 +42,7 @@ collapse_vars_2: {
var a = "FAIL"; var a = "FAIL";
try { try {
a = "PASS"; a = "PASS";
[ ...42, "PASS"].slice(); [ ...42, "PASS" ].slice();
} catch (e) { } catch (e) {
console.log(a); console.log(a);
} }
@ -58,7 +58,7 @@ collapse_vars_3: {
input: { input: {
var a = "FAIL"; var a = "FAIL";
try { try {
[ ...(a = "PASS", 42), "PASS"].slice(); [ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) { } catch (e) {
console.log(a); console.log(a);
} }
@ -66,7 +66,7 @@ collapse_vars_3: {
expect: { expect: {
var a = "FAIL"; var a = "FAIL";
try { try {
[ ...(a = "PASS", 42), "PASS"].slice(); [ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) { } catch (e) {
console.log(a); console.log(a);
} }
@ -1253,3 +1253,24 @@ issue_5602: {
] ]
node_version: ">=6" node_version: ">=6"
} }
issue_5850: {
options = {
evaluate: true,
join_vars: true,
unused: true,
}
input: {
var a = [ ..."FAIL" ];
a[0] = "P";
a[2] = a[3] = "S";
console.log(a.join(""));
}
expect: {
var a = [ ..."FAIL" ];
a[0] = "P";
a[2] = a[3] = "S";
console.log(a.join(""));
}
node_version: ">=6"
}

View File

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

View File

@ -329,6 +329,42 @@ forin_const_2: {
node_version: ">=6" node_version: ">=6"
} }
forin_const_3: {
options = {
module: true,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
const o = {
p: 42,
q: "PASS",
};
for (const k in o)
(function f() {
console.log(k, o[k]);
})();
}
expect: {
"use strict";
let o = {
p: 42,
q: "PASS",
};
for (let k in o)
(function f() {
console.log(k, o[k]);
})();
}
expect_stdout: [
"p 42",
"q PASS",
]
node_version: ">=4"
}
forin_let_1: { forin_let_1: {
options = { options = {
join_vars: true, join_vars: true,
@ -682,3 +718,165 @@ issue_5516: {
expect_stdout: "function" expect_stdout: "function"
node_version: ">=4" node_version: ">=4"
} }
issue_5697_1: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
const a = k;
console.log(a);
}
})();
}
}());
}
expect: {
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
}
issue_5697_2: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
"use strict";
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
let a = k;
console.log(a);
}
})();
}
}());
}
expect: {
"use strict";
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=4"
}
issue_5697_3: {
options = {
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
varify: true,
}
input: {
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
const a = k;
console.log(a);
}
})();
}
}());
}
expect: {
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
}
issue_5697_4: {
options = {
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
varify: true,
}
input: {
"use strict";
console.log(function() {
f();
return typeof a;
function f() {
(function() {
for (var k in { foo: 42 }) {
let a = k;
console.log(a);
}
})();
}
}());
}
expect: {
"use strict";
console.log(function() {
(function() {
for (var k in { foo: 42 }) {
var a = k;
console.log(a);
}
})();
return typeof a;
}());
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=4"
}

View File

@ -896,7 +896,7 @@ dont_inline_nested: {
node_version: ">=4" node_version: ">=4"
} }
drop_body: { drop_body_1: {
options = { options = {
side_effects: true, side_effects: true,
yields: true, yields: true,
@ -906,6 +906,27 @@ drop_body: {
console.log("bar"); console.log("bar");
})([ console.log("baz") ]); })([ console.log("baz") ]);
} }
expect: {
void ([ [ , [][0] = console.log("foo") ] ] = [ [ console.log("baz") ] ]);
}
expect_stdout: [
"baz",
"foo",
]
node_version: ">=6"
}
drop_body_2: {
options = {
passes: 2,
side_effects: true,
yields: true,
}
input: {
(function*([ , a = console.log("foo") ]) {
console.log("bar");
})([ console.log("baz") ]);
}
expect: { expect: {
[ [ , [][0] = console.log("foo") ] ] = [ [ console.log("baz") ] ]; [ [ , [][0] = console.log("foo") ] ] = [ [ console.log("baz") ] ];
} }
@ -1365,7 +1386,7 @@ issue_5076_1: {
expect: { expect: {
var a; var a;
console.log("PASS"), console.log("PASS"),
a = 42["a"]; a = 42..a;
} }
expect_stdout: "PASS" expect_stdout: "PASS"
node_version: ">=6" node_version: ">=6"
@ -1769,3 +1790,460 @@ issue_5663: {
] ]
node_version: ">=6" node_version: ">=6"
} }
issue_5679_1: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
b;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_2: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return undefined;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return void 0;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_3: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return undefined;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
return void 0;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_4: {
options = {
conditionals: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return undefined;
else
return undefined;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
return b, void 0;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_5: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_6: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return;
else
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
if (!b)
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5684: {
options = {
conditionals: true,
if_return: true,
}
input: {
(async function*() {
switch (42) {
default:
if (console.log("PASS"))
return;
return null;
case false:
}
})().next();
}
expect: {
(async function*() {
switch (42) {
default:
return console.log("PASS") ? void 0 : null;
case false:
}
})().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5707_1: {
options = {
hoist_props: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
yields: true,
}
input: {
var a, b;
function* f(c = (b = 42, console.log("PASS"))) {}
b = f();
}
expect: {
(function(c = console.log("PASS")) {})();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5707_2: {
options = {
hoist_props: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
yields: true,
}
input: {
var a, b;
function* f(c = (b = 42, console.log("PASS"))) {}
b = f();
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5710: {
options = {
conditionals: true,
if_return: true,
}
input: {
(async function*() {
try {
switch (42) {
case 42:
{
if (console.log("PASS"))
return;
return null;
}
break;
}
} finally {}
})().next();
}
expect: {
(async function*() {
try {
switch (42) {
case 42:
if (console.log("PASS"))
return;
return null;
break;
}
} finally {}
})().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5749_1: {
options = {
collapse_vars: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
yields: true,
}
input: {
var a;
function* f() {}
a = f(new function() {
var b = a |= 0, c = a += console.log("PASS");
}());
}
expect: {
(function() {})(function() {
console.log("PASS");
}());
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5749_2: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
yields: true,
}
input: {
var a;
function* f() {}
a = f(new function() {
var b = a |= 0, c = a += console.log("PASS");
}());
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5754: {
options = {
if_return: true,
}
input: {
async function* f(a, b) {
try {
if (a)
return void 0;
} finally {
console.log(b);
}
}
f(42, "foo").next();
f(null, "bar").next();
console.log("baz");
}
expect: {
async function* f(a, b) {
try {
if (a)
return void 0;
} finally {
console.log(b);
}
}
f(42, "foo").next();
f(null, "bar").next();
console.log("baz");
}
expect_stdout: [
"bar",
"baz",
"foo",
]
node_version: ">=10"
}
issue_5842: {
options = {
inline: true,
}
input: {
var a = "FAIL";
(async function*() {
(function() {
try {
try {
return console;
} finally {
a = "PASS";
}
} catch (e) {}
FAIL;
})();
})().next();
console.log(a);
}
expect: {
var a = "FAIL";
(async function*() {
(function() {
try {
try {
return console;
} finally {
a = "PASS";
}
} catch (e) {}
FAIL;
})();
})().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}

View File

@ -1,16 +1,10 @@
// (beautified) // (beautified)
var b = 0;
var expr2 = (0 - 1 - .1 - .1).toString(); var expr2 = (0 - 1 - .1 - .1).toString();
for (var key2 in expr2) { console.log(expr2);
--b; // output: -1.2000000000000002
}
console.log(b);
// output: -19
// //
// minify: -4 // minify: -1.2
// //
// options: { // options: {
// "compress": { // "compress": {

View File

@ -14,7 +14,7 @@ if (typeof phantom == "undefined") {
args.splice(debug, 1); args.splice(debug, 1);
debug = true; debug = true;
} }
if (!args.length) args.push("-mcb", "beautify=false,webkit"); if (!args.length) args.push("-mcO", "webkit");
args.unshift("bin/uglifyjs"); args.unshift("bin/uglifyjs");
args.push("--validate", "--timings"); args.push("--validate", "--timings");
var child_process = require("child_process"); var child_process = require("child_process");
@ -63,7 +63,10 @@ if (typeof phantom == "undefined") {
function npm(args, done) { function npm(args, done) {
args.push("--loglevel=error"); args.push("--loglevel=error");
child_process.spawn(cmd, args, { stdio: [ "ignore", 1, 2 ] }).on("exit", done); child_process.spawn(cmd, args, {
shell: true,
stdio: [ "ignore", 1, 2 ],
}).on("exit", done);
} }
(function install() { (function install() {

View File

@ -206,7 +206,13 @@ describe("bin/uglifyjs", function() {
}, 1000); }, 1000);
}); });
it("Should work with --keep-fargs (mangle only)", function(done) { it("Should work with --keep-fargs (mangle only)", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fargs -m'; var command = [
uglifyjscmd,
"test/input/issue-1431/sample.js",
"--keep-fargs",
"--mangle",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n"); assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n");
@ -214,7 +220,14 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with --keep-fargs (mangle & compress)", function(done) { it("Should work with --keep-fargs (mangle & compress)", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fargs -m -c'; var command = [
uglifyjscmd,
"test/input/issue-1431/sample.js",
"--keep-fargs",
"--mangle",
"--no-module",
"--compress",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(){return x(function(a){return a*a})}}function g(op){return op(1)+op(2)}console.log(5==f(g)());\n"); assert.strictEqual(stdout, "function f(x){return function(){return x(function(a){return a*a})}}function g(op){return op(1)+op(2)}console.log(5==f(g)());\n");
@ -222,7 +235,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with keep_fargs under mangler options", function(done) { it("Should work with keep_fargs under mangler options", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fargs=true'; var command = [
uglifyjscmd,
"test/input/issue-1431/sample.js",
"--mangle", "keep_fargs=true",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n"); assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n");
@ -230,7 +248,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with --keep-fnames (mangle only)", function(done) { it("Should work with --keep-fnames (mangle only)", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m'; var command = [
uglifyjscmd,
"test/input/issue-1431/sample.js",
"--keep-fnames",
"--mangle",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n"); assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
@ -238,7 +261,14 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with --keep-fnames (mangle & compress)", function(done) { it("Should work with --keep-fnames (mangle & compress)", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c'; var command = [
uglifyjscmd,
"test/input/issue-1431/sample.js",
"--keep-fnames",
"--mangle",
"--no-module",
"--compress",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(n){return function(){return n(function n(r){return r*r})}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n"); assert.strictEqual(stdout, "function f(n){return function(){return n(function n(r){return r*r})}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
@ -557,7 +587,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (delete x)", function(done) { it("Should throw syntax error (delete x)", function(done) {
var command = uglifyjscmd + " test/input/invalid/delete.js"; var command = [
uglifyjscmd,
"test/input/invalid/delete.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -571,7 +605,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (function g(arguments))", function(done) { it("Should throw syntax error (function g(arguments))", function(done) {
var command = uglifyjscmd + " test/input/invalid/function_1.js"; var command = [
uglifyjscmd,
"test/input/invalid/function_1.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -585,7 +623,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (function eval())", function(done) { it("Should throw syntax error (function eval())", function(done) {
var command = uglifyjscmd + " test/input/invalid/function_2.js"; var command = [
uglifyjscmd,
"test/input/invalid/function_2.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -599,7 +641,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (iife arguments())", function(done) { it("Should throw syntax error (iife arguments())", function(done) {
var command = uglifyjscmd + " test/input/invalid/function_3.js"; var command = [
uglifyjscmd,
"test/input/invalid/function_3.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -613,7 +659,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (catch (eval))", function(done) { it("Should throw syntax error (catch (eval))", function(done) {
var command = uglifyjscmd + " test/input/invalid/try.js"; var command = [
uglifyjscmd,
"test/input/invalid/try.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -627,7 +677,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (var eval)", function(done) { it("Should throw syntax error (var eval)", function(done) {
var command = uglifyjscmd + " test/input/invalid/var.js"; var command = [
uglifyjscmd,
"test/input/invalid/var.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -641,7 +695,11 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should throw syntax error (var { eval })", function(done) { it("Should throw syntax error (var { eval })", function(done) {
var command = uglifyjscmd + " test/input/invalid/destructured_var.js"; var command = [
uglifyjscmd,
"test/input/invalid/destructured_var.js",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
@ -807,7 +865,8 @@ describe("bin/uglifyjs", function() {
var command = [ var command = [
uglifyjscmd, uglifyjscmd,
"test/input/issue-2310/input.js", "test/input/issue-2310/input.js",
"-c", "--compress",
"--no-module",
"--source-map", "url=inline", "--source-map", "url=inline",
].join(" "); ].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
@ -840,7 +899,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with --mangle reserved=[]", function(done) { it("Should work with --mangle reserved=[]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]"; var command = [
uglifyjscmd,
"test/input/issue-505/input.js",
"--mangle", "reserved=[callback]",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'function test(callback){"aaaaaaaaaaaaaaaa";callback(err,data);callback(err,data)}\n'); assert.strictEqual(stdout, 'function test(callback){"aaaaaaaaaaaaaaaa";callback(err,data);callback(err,data)}\n');
@ -848,7 +912,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with --mangle reserved=false", function(done) { it("Should work with --mangle reserved=false", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false"; var command = [
uglifyjscmd,
"test/input/issue-505/input.js",
"--mangle", "reserved=false",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'function test(a){"aaaaaaaaaaaaaaaa";a(err,data);a(err,data)}\n'); assert.strictEqual(stdout, 'function test(a){"aaaaaaaaaaaaaaaa";a(err,data);a(err,data)}\n');
@ -865,7 +934,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with mangle.properties.regex from --config-file", function(done) { it("Should work with mangle.properties.regex from --config-file", function(done) {
var command = uglifyjscmd + " test/input/issue-3315/input.js --config-file test/input/issue-3315/config.json"; var command = [
uglifyjscmd,
"test/input/issue-3315/input.js",
"--config-file", "test/input/issue-3315/config.json",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,t:2};return a.prop+a.t}\n'); assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,t:2};return a.prop+a.t}\n');
@ -882,7 +956,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with explicit --rename", function(done) { it("Should work with explicit --rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js --rename"; var command = [
uglifyjscmd,
"test/input/rename/input.js",
"--no-module",
"--rename",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+c}}\n"); assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+c}}\n");
@ -890,7 +969,14 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with explicit --no-rename", function(done) { it("Should work with explicit --no-rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename"; var command = [
uglifyjscmd,
"test/input/rename/input.js",
"--compress", "passes=2",
"--mangle",
"--no-module",
"--no-rename",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(n){return function(n){return n+n}(n)}\n"); assert.strictEqual(stdout, "function f(n){return function(n){return n+n}(n)}\n");
@ -898,7 +984,13 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with implicit --rename", function(done) { it("Should work with implicit --rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2"; var command = [
uglifyjscmd,
"test/input/rename/input.js",
"--compress", "passes=2",
"--mangle",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(n){return n+n}\n"); assert.strictEqual(stdout, "function f(n){return n+n}\n");
@ -906,7 +998,12 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with implicit --no-rename", function(done) { it("Should work with implicit --no-rename", function(done) {
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2"; var command = [
uglifyjscmd,
"test/input/rename/input.js",
"--compress", "passes=2",
"--no-module",
].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(x){return x+x}(x)}\n"); assert.strictEqual(stdout, "function f(x){return function(x){return x+x}(x)}\n");
@ -971,12 +1068,7 @@ describe("bin/uglifyjs", function() {
]).join("\n"); ]).join("\n");
exec(uglifyjscmd + " -mc", function(err, stdout) { exec(uglifyjscmd + " -mc", function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, [ assert.strictEqual(stdout, "console.log(function(){var p={p:25},n={p:121},o={p:1024};return p.p+n.p+o.p}());\n");
"console.log(function(){",
"var p={p:25},n={p:121},o={p:1024};",
"return p.p+n.p+o.p",
"}());\n",
].join(""));
assert.strictEqual(run_code(stdout), run_code(code)); assert.strictEqual(run_code(stdout), run_code(code));
done(); done();
}).stdin.end(code); }).stdin.end(code);

View File

@ -400,7 +400,7 @@ describe("comments", function() {
assert.strictEqual(ast.print_to_string({comments: "all"}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8"); assert.strictEqual(ast.print_to_string({comments: "all"}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8");
}); });
it("Should be able to filter commments with the 'some' option", function() { it("Should be able to filter comments with the 'some' option", function() {
var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/"); var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/");
assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/"); assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/");
}); });
@ -476,7 +476,9 @@ describe("comments", function() {
for (var i = 1; i <= 5000; ++i) js += "// " + i + "\n"; for (var i = 1; i <= 5000; ++i) js += "// " + i + "\n";
for (; i <= 10000; ++i) js += "/* " + i + " */ /**/"; for (; i <= 10000; ++i) js += "/* " + i + " */ /**/";
js += "x; }"; js += "x; }";
var result = UglifyJS.minify(js, { mangle: false }); var result = UglifyJS.minify(js, {
mangle: false,
});
assert.strictEqual(result.code, "function lots_of_comments(x){return 7-x}"); assert.strictEqual(result.code, "function lots_of_comments(x){return 7-x}");
}); });
}); });

View File

@ -348,7 +348,7 @@ describe("Directives", function() {
'"use strict";doSomething("foo");' '"use strict";doSomething("foo");'
], ],
[ [
// Nothing gets optimised in the compressor because "use asm" is the first statement // Nothing gets optimized in the compressor because "use asm" is the first statement
'"use asm";"use\\x20strict";1+1;', '"use asm";"use\\x20strict";1+1;',
'"use asm";"use\\x20strict";1+1;' '"use asm";"use\\x20strict";1+1;'
], ],
@ -373,7 +373,9 @@ describe("Directives", function() {
'function f(){}' 'function f(){}'
], ],
].forEach(function(test) { ].forEach(function(test) {
var result = UglifyJS.minify(test[0]); var result = UglifyJS.minify(test[0], {
module: false,
});
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, test[1], test[0]); assert.strictEqual(result.code, test[1], test[0]);
}); });

View File

@ -5,31 +5,44 @@ var path = require("path");
describe("bin/uglifyjs with input file globs", function() { describe("bin/uglifyjs with input file globs", function() {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs'; var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("bin/uglifyjs with one input file extension glob.", function(done) { it("bin/uglifyjs with one input file extension glob.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/foo.*" -cm'; var command = [
uglifyjscmd,
'"test/input/issue-1242/foo.*"',
"--compress",
"--mangle",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'var print=console.log.bind(console);function foo(o){print("Foo:",2*o)}\n'); assert.strictEqual(stdout, 'var print=console.log.bind(console);function foo(o){print("Foo:",2*o)}\n');
done(); done();
}); });
}); });
it("bin/uglifyjs with one input file name glob.", function(done) { it("bin/uglifyjs with one input file name glob.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/b*.es5" -cm'; var command = [
uglifyjscmd,
'"test/input/issue-1242/b*.es5"',
"--compress",
"--mangle",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'function bar(n){return 3*n}function baz(n){return n/2}\n'); assert.strictEqual(stdout, 'function bar(n){return 3*n}function baz(n){return n/2}\n');
done(); done();
}); });
}); });
it("bin/uglifyjs with multiple input file globs.", function(done) { it("bin/uglifyjs with multiple input file globs.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=3'; var command = [
uglifyjscmd,
'"test/input/issue-1242/???.es5"',
'"test/input/issue-1242/*.js"',
"--compress", "toplevel,passes=3",
"--mangle",
"--no-module",
].join(" ");
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n'); assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n');
done(); done();
}); });

View File

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

View File

@ -6,8 +6,10 @@ describe("Input file as map", function() {
var jsMap = { var jsMap = {
'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};' '/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'
}; };
var result = UglifyJS.minify(jsMap, {sourceMap: true}); var result = UglifyJS.minify(jsMap, {
sourceMap: true,
});
if (result.error) throw result.error;
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
assert.deepEqual(map.sources, ['/scripts/foo.js']); assert.deepEqual(map.sources, ['/scripts/foo.js']);
@ -26,8 +28,10 @@ describe("Input file as map", function() {
'var foo = {"x": 1, y: 2, \'z\': 3};', 'var foo = {"x": 1, y: 2, \'z\': 3};',
'var bar = 15;' 'var bar = 15;'
]; ];
var result = UglifyJS.minify(jsSeq, {sourceMap: true}); var result = UglifyJS.minify(jsSeq, {
sourceMap: true,
});
if (result.error) throw result.error;
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;'); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
assert.deepEqual(map.sources, ['0', '1']); assert.deepEqual(map.sources, ['0', '1']);
@ -37,8 +41,12 @@ describe("Input file as map", function() {
var jsMap = { var jsMap = {
'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};' '/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'
}; };
var result = UglifyJS.minify(jsMap, {sourceMap: {includeSources: true}}); var result = UglifyJS.minify(jsMap, {
sourceMap: {
includeSources: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};']); assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};']);

View File

@ -48,8 +48,8 @@ describe("minify", function() {
var result = UglifyJS.minify(code, { var result = UglifyJS.minify(code, {
mangle: { mangle: {
cache: cache, cache: cache,
toplevel: true toplevel: true,
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
original += code; original += code;
@ -79,9 +79,9 @@ describe("minify", function() {
var code = read("test/input/issue-1242/" + file); var code = read("test/input/issue-1242/" + file);
var result = UglifyJS.minify(code, { var result = UglifyJS.minify(code, {
mangle: { mangle: {
toplevel: true toplevel: true,
}, },
nameCache: cache nameCache: cache,
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
original += code; original += code;
@ -110,10 +110,12 @@ describe("minify", function() {
var result = UglifyJS.minify(code, { var result = UglifyJS.minify(code, {
compress: false, compress: false,
mangle: { mangle: {
properties: true, properties: {
toplevel: true domprops: true,
},
toplevel: true,
}, },
nameCache: cache nameCache: cache,
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
original += code; original += code;
@ -160,8 +162,9 @@ describe("minify", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};'; var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
var result = UglifyJS.minify(js, { var result = UglifyJS.minify(js, {
output: { output: {
keep_quoted_props: true keep_quoted_props: true,
}}); },
});
assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};'); assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};');
}); });
it("Should preserve quote styles when quote_style is 3", function() { it("Should preserve quote styles when quote_style is 3", function() {
@ -169,8 +172,9 @@ describe("minify", function() {
var result = UglifyJS.minify(js, { var result = UglifyJS.minify(js, {
output: { output: {
keep_quoted_props: true, keep_quoted_props: true,
quote_style: 3 quote_style: 3,
}}); },
});
assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};'); assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};');
}); });
it("Should not preserve quotes in object literals when disabled", function() { it("Should not preserve quotes in object literals when disabled", function() {
@ -178,8 +182,9 @@ describe("minify", function() {
var result = UglifyJS.minify(js, { var result = UglifyJS.minify(js, {
output: { output: {
keep_quoted_props: false, keep_quoted_props: false,
quote_style: 3 quote_style: 3,
}}); },
});
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
}); });
}); });
@ -188,32 +193,30 @@ describe("minify", function() {
it("Shouldn't mangle quoted properties", function() { it("Shouldn't mangle quoted properties", function() {
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
var result = UglifyJS.minify(js, { var result = UglifyJS.minify(js, {
compress: { compress: true,
properties: false
},
mangle: { mangle: {
properties: { properties: {
keep_quoted: true domprops: true,
} keep_quoted: true,
},
}, },
output: { output: {
keep_quoted_props: true, keep_quoted_props: true,
quote_style: 3 quote_style: 3,
} },
}); });
assert.strictEqual(result.code, assert.strictEqual(result.code, 'a["foo"]="bar",a.a="red",x={"bar":10};');
'a["foo"]="bar",a.a="red",x={"bar":10};');
}); });
it("Should not mangle quoted property within dead code", function() { it("Should not mangle quoted property within dead code", function() {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change;', { var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change = 42;', {
mangle: { mangle: {
properties: { properties: {
keep_quoted: true keep_quoted: true,
} },
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g;"); assert.strictEqual(result.code, "g.keep=g.g=42;");
}); });
}); });
@ -223,7 +226,7 @@ describe("minify", function() {
output: { output: {
comments: "all", comments: "all",
beautify: false, beautify: false,
} },
}); });
var code = result.code; var code = result.code;
assert.strictEqual(code, "// comment1 comment2\nbar();"); assert.strictEqual(code, "// comment1 comment2\nbar();");
@ -233,7 +236,7 @@ describe("minify", function() {
output: { output: {
comments: "all", comments: "all",
beautify: false, beautify: false,
} },
}); });
var code = result.code; var code = result.code;
assert.strictEqual(code, "var a=function(){foo()}();"); assert.strictEqual(code, "var a=function(){foo()}();");
@ -301,7 +304,7 @@ describe("minify", function() {
compress: false, compress: false,
mangle: false, mangle: false,
output: { output: {
ast: true ast: true,
}, },
}).ast; }).ast;
assert.strictEqual(ast.TYPE, "Toplevel"); assert.strictEqual(ast.TYPE, "Toplevel");
@ -312,9 +315,9 @@ describe("minify", function() {
var stat = ast.body[0].body[0]; var stat = ast.body[0].body[0];
UglifyJS.minify(ast, { UglifyJS.minify(ast, {
compress: { compress: {
sequences: false sequences: false,
}, },
mangle: false mangle: false,
}); });
assert.ok(stat.body); assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()"); assert.strictEqual(stat.print_to_string(), "a=x()");

View File

@ -236,9 +236,9 @@ describe("test/reduce.js", function() {
}); });
it("Should report trailing whitespace difference in stringified format", function() { it("Should report trailing whitespace difference in stringified format", function() {
var code = [ var code = [
"for (var a in (1 - .8).toString()) {", "[].forEach.call((1 - .8).toString(), function() {",
" console.log();", " console.log();",
"}", "});",
].join("\n"); ].join("\n");
var result = reduce_test(code, { var result = reduce_test(code, {
compress: { compress: {
@ -333,6 +333,7 @@ describe("test/reduce.js", function() {
unsafe_math: true, unsafe_math: true,
}, },
mangle: false, mangle: false,
module: false,
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, [ assert.strictEqual(result.code, [
@ -346,7 +347,8 @@ describe("test/reduce.js", function() {
'// "compress": {', '// "compress": {',
'// "unsafe_math": true', '// "unsafe_math": true',
'// },', '// },',
'// "mangle": false', '// "mangle": false,',
'// "module": false',
"// }", "// }",
].join("\n")); ].join("\n"));
}); });

View File

@ -245,7 +245,7 @@ describe("sourcemaps", function() {
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js")); assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
}); });
it("Should work in presence of unrecognised annotations", function() { it("Should work in presence of unrecognized annotations", function() {
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), { var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false, compress: false,
mangle: false, mangle: false,
@ -296,8 +296,8 @@ describe("sourcemaps", function() {
it("Should append source map to output js when sourceMapInline is enabled", function() { it("Should append source map to output js when sourceMapInline is enabled", function() {
var result = UglifyJS.minify('var a = function(foo) { return foo; };', { var result = UglifyJS.minify('var a = function(foo) { return foo; };', {
sourceMap: { sourceMap: {
url: "inline" url: "inline",
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
var code = result.code; var code = result.code;
@ -305,7 +305,7 @@ describe("sourcemaps", function() {
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BLENBQUsifQ=="); "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BLENBQUsifQ==");
}); });
it("Should not append source map to output js when sourceMapInline is not enabled", function() { it("Should not append source map to output js when sourceMapInline is not enabled", function() {
var result = UglifyJS.minify('var a = function(foo) { return foo; };'); var result = UglifyJS.minify("var a = function(foo) { return foo; };");
if (result.error) throw result.error; if (result.error) throw result.error;
var code = result.code; var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};"); assert.strictEqual(code, "var a=function(n){return n};");
@ -316,11 +316,11 @@ describe("sourcemaps", function() {
directives: false, directives: false,
}, },
output: { output: {
max_line_len: 20 max_line_len: 20,
}, },
sourceMap: { sourceMap: {
url: "inline" url: "inline",
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/issue-505/output.js")); assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
@ -334,7 +334,7 @@ describe("sourcemaps", function() {
sourceMap: { sourceMap: {
includeSources: true, includeSources: true,
url: "inline", url: "inline",
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
var map = JSON.parse(result.map); var map = JSON.parse(result.map);
@ -348,7 +348,7 @@ describe("sourcemaps", function() {
sourceMap: { sourceMap: {
content: "inline", content: "inline",
includeSources: true, includeSources: true,
} },
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
map = JSON.parse(result.map); map = JSON.parse(result.map);

View File

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

View File

@ -20,6 +20,9 @@ Error.stackTraceLimit = Infinity;
module.exports = function reduce_test(testcase, minify_options, reduce_options) { module.exports = function reduce_test(testcase, minify_options, reduce_options) {
minify_options = minify_options || {}; minify_options = minify_options || {};
reduce_options = reduce_options || {}; reduce_options = reduce_options || {};
var parse_options = {
module: minify_options.module || minify_options.module === undefined,
}
var print_options = {}; var print_options = {};
[ [
"ie", "ie",
@ -190,7 +193,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
} }
else if (node instanceof U.AST_BlockStatement) { else if (node instanceof U.AST_BlockStatement) {
if (in_list && node.body.filter(function(node) { if (in_list && node.body.filter(function(node) {
return node instanceof U.AST_Const; return node instanceof U.AST_Const || node instanceof U.AST_Let;
}).length == 0) { }).length == 0) {
node.start._permute++; node.start._permute++;
CHANGED = true; CHANGED = true;
@ -332,19 +335,21 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
} }
else if (node instanceof U.AST_ForEnumeration) { else if (node instanceof U.AST_ForEnumeration) {
var expr; var expr;
switch ((node.start._permute * steps | 0) % 3) { switch ((node.start._permute * steps | 0) % 4) {
case 0: case 0:
if (node.init instanceof U.AST_Definitions) {
if (node.init instanceof U.AST_Const) break;
if (node.init.definitions[0].name instanceof U.AST_Destructured) break;
}
expr = node.init;
break;
case 1:
expr = node.object; expr = node.object;
break; break;
case 1:
expr = wrap_with_console_log(node.object);
break;
case 2: case 2:
if (!has_loopcontrol(node.body, node, parent)) expr = node.body; if (has_loopcontrol(node.body, node, parent)) break;
expr = node.body;
break;
case 3:
if (!(node.init instanceof U.AST_Var)) break;
if (node.init.definitions[0].name instanceof U.AST_Destructured) break;
expr = node.init;
break; break;
} }
node.start._permute += step; node.start._permute += step;
@ -358,9 +363,17 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
node.condition, node.condition,
node.body, node.body,
node.alternative, node.alternative,
][ (node.start._permute * steps | 0) % 3 ]; node,
][ (node.start._permute * steps | 0) % 4 ];
node.start._permute += step; node.start._permute += step;
if (expr) { if (expr === node) {
if (node.alternative) {
expr = node.clone();
expr.alternative = null;
CHANGED = true;
return expr;
}
} else if (expr) {
// replace if statement with its condition, then block or else block // replace if statement with its condition, then block or else block
CHANGED = true; CHANGED = true;
return to_statement(expr); return to_statement(expr);
@ -539,7 +552,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
var before_iterations, diff_error_message, passes = 3, testcase_ast; var before_iterations, diff_error_message, passes = 3, testcase_ast;
for (var pass = 1; pass <= passes; pass++) { for (var pass = 1; pass <= passes; pass++) {
if (before_iterations !== testcase) { if (before_iterations !== testcase) {
testcase_ast = U.parse(testcase); testcase_ast = U.parse(testcase, parse_options);
if (diff_error_message === testcase) { if (diff_error_message === testcase) {
// only difference detected is in error message, so expose that and try again // only difference detected is in error message, so expose that and try again
testcase_ast.transform(new U.TreeTransformer(function(node, descend) { testcase_ast.transform(new U.TreeTransformer(function(node, descend) {
@ -561,7 +574,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
testcase = code; testcase = code;
differs = diff; differs = diff;
} else { } else {
testcase_ast = U.parse(testcase); testcase_ast = U.parse(testcase, parse_options);
} }
} }
diff_error_message = null; diff_error_message = null;
@ -621,6 +634,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
var beautified = U.minify(testcase, { var beautified = U.minify(testcase, {
compress: false, compress: false,
mangle: false, mangle: false,
module: minify_options.module,
output: function() { output: function() {
var options = JSON.parse(JSON.stringify(print_options)); var options = JSON.parse(JSON.stringify(print_options));
options.beautify = true; options.beautify = true;
@ -773,7 +787,7 @@ function run_code(code, toplevel, result_cache, timeout) {
if (!value) { if (!value) {
var start = Date.now(); var start = Date.now();
result_cache[key] = value = { result_cache[key] = value = {
result: sandbox.run_code(sandbox.patch_module_statements(code), toplevel, timeout), result: sandbox.run_code(code, toplevel, timeout),
elapsed: Date.now() - start, elapsed: Date.now() - start,
}; };
} }
@ -801,13 +815,7 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
}; };
function run(code, timeout) { function run(code, timeout) {
if (minify_options.module) code = [ return run_code(sandbox.patch_module_statements(code, minify_options.module), toplevel, result_cache, timeout);
'"use strict";',
"(async()=>{",
code,
'})().catch(e=>process.on("exit",()=>{throw e}));',
].join("\n");
return run_code(code, toplevel, result_cache, timeout);
} }
} }

View File

@ -1,11 +1,8 @@
require("./run")([ require("./run")([
"-b", "-mb braces",
"-b braces", "--toplevel -c",
"-m", "--no-module -mc",
"-mc passes=3",
"-mc passes=3,toplevel",
"-mc passes=3,unsafe", "-mc passes=3,unsafe",
"-mc keep_fargs=false,passes=3",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto", "-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].map(function(options) { ].map(function(options) {
var args = options.split(/ /); var args = options.split(/ /);

View File

@ -41,6 +41,11 @@ rm -rf tmp/buble \
@@ -309 +309 @@ export default class BlockStatement extends Node { @@ -309 +309 @@ export default class BlockStatement extends Node {
- let cont = false; // TODO implement proper continue... - let cont = false; // TODO implement proper continue...
+ let cont = !declarations; // TODO implement proper continue... + let cont = !declarations; // TODO implement proper continue...
--- a/src/program/types/VariableDeclaration.js
+++ b/src/program/types/VariableDeclaration.js
@@ -38 +38 @@ export default class VariableDeclaration extends Node {
- code.remove(c, declarator.id.start);
+ code.remove(c, declarator.id.start, lastDeclaratorIsPattern);
EOF 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" \

View File

@ -50,7 +50,8 @@ node --version
npm config set audit false npm config set audit false
npm config set fund false npm config set fund false
npm config set loglevel error npm config set loglevel error
npm config set optional false npm config set omit optional || true
npm config set optional false || true
npm config set save false 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

View File

@ -4,6 +4,7 @@ require("./run")([
].map(function(options) { ].map(function(options) {
var args = options.split(/ /); var args = options.split(/ /);
args.unshift("test/jetstream.js"); args.unshift("test/jetstream.js");
args.push("-b", "beautify=false,webkit"); args.push("-O", "webkit");
args.push("--no-module");
return args; return args;
})); }));

View File

@ -35,18 +35,27 @@ npm_install() {
done done
} }
workaround() {
FILE="$1"
echo 'Monkey patching' $FILE
CODE=`cat $FILE`
sed -E 's/for ?\((var [^;{]+;)/\1for\(;/g' > $FILE <<EOF
$CODE
EOF
}
rm -rf tmp/sucrase \ rm -rf tmp/sucrase \
&& git clone https://github.com/alangpierce/sucrase.git tmp/sucrase \ && git clone https://github.com/alangpierce/sucrase.git tmp/sucrase \
&& cd tmp/sucrase \ && cd tmp/sucrase \
&& rm -rf .git/hooks \ && rm -rf .git/hooks \
&& git checkout 38b66f3009feb76750a799deea211adcc83574f1 \ && git checkout 7284b3733aa114b3f4f5371e36ff5a4704ec860e \
&& patch -l -p1 <<EOF && patch -l -p1 <<EOF
--- a/package.json --- a/package.json
+++ b/package.json +++ b/package.json
@@ -25 +24,0 @@ @@ -25 +24,0 @@
- "prepublishOnly": "yarn clean && yarn build", - "prepublishOnly": "yarn clean && yarn build",
@@ -65 +63,0 @@ @@ -69 +67,0 @@
- "test262-harness": "^6.5.0", - "test262-harness": "^10.0.0",
--- a/script/build.ts --- a/script/build.ts
+++ b/script/build.ts +++ b/script/build.ts
@@ -16 +15,0 @@ async function main(): Promise<void> { @@ -16 +15,0 @@ async function main(): Promise<void> {
@ -57,11 +66,11 @@ rm -rf tmp/sucrase \
- () => buildIntegration("./integrations/webpack-loader"), - () => buildIntegration("./integrations/webpack-loader"),
- () => buildIntegration("./integrations/webpack-object-rest-spread-plugin"), - () => buildIntegration("./integrations/webpack-object-rest-spread-plugin"),
- () => buildWebsite(), - () => buildWebsite(),
@@ -66,3 +59,0 @@ async function buildSucrase(): Promise<void> { @@ -62,3 +55,0 @@ async function buildSucrase(): Promise<void> {
- // Also add in .d.ts files from tsc, which only need to be compiled once. - // Also add in .d.ts files from tsc, which only need to be compiled once.
- await run(\`\${TSC} --project ./src --outDir ./dist-types\`); - await run(\`\${TSC} --project ./src --outDir ./dist-types\`);
- await mergeDirectoryContents("./dist-types/src", "./dist"); - await mergeDirectoryContents("./dist-types/src", "./dist/types");
@@ -70 +61 @@ async function buildSucrase(): Promise<void> { @@ -66 +57 @@ async function buildSucrase(): Promise<void> {
- await run("yarn link"); - await run("yarn link");
+ await run("npm link"); + await run("npm link");
--- a/src/identifyShadowedGlobals.ts --- a/src/identifyShadowedGlobals.ts
@ -70,28 +79,38 @@ rm -rf tmp/sucrase \
+export { identifyShadowedGlobals as HACK }; +export { identifyShadowedGlobals as HACK };
--- a/src/parser/tokenizer/state.ts --- a/src/parser/tokenizer/state.ts
+++ b/src/parser/tokenizer/state.ts +++ b/src/parser/tokenizer/state.ts
@@ -100,0 +101 @@ export default class State { @@ -106,0 +107 @@ export default class State {
+export { State as HACK }; +export { State as HACK };
--- a/src/transformers/JSXTransformer.ts --- a/src/transformers/JSXTransformer.ts
+++ b/src/transformers/JSXTransformer.ts +++ b/src/transformers/JSXTransformer.ts
@@ -253,0 +254 @@ export default class JSXTransformer extends Transformer { @@ -560,0 +561 @@ export default class JSXTransformer extends Transformer {
+export { JSXTransformer as HACK }; +export { JSXTransformer as HACK };
--- a/src/util/getClassInfo.ts --- a/src/util/getClassInfo.ts
+++ b/src/util/getClassInfo.ts +++ b/src/util/getClassInfo.ts
@@ -164,0 +165 @@ export default function getClassInfo( @@ -195,0 +196 @@ export default function getClassInfo(
+export { getClassInfo as HACK }; +export { getClassInfo as HACK };
--- a/src/util/getDeclarationInfo.ts --- a/src/util/getDeclarationInfo.ts
+++ b/src/util/getDeclarationInfo.ts +++ b/src/util/getDeclarationInfo.ts
@@ -40,0 +41 @@ export default function getDeclarationInfo(tokens: TokenProcessor): DeclarationI @@ -40,0 +41 @@ export default function getDeclarationInfo(tokens: TokenProcessor): DeclarationI
+export { getDeclarationInfo as HACK }; +export { getDeclarationInfo as HACK };
--- a/src/util/getImportExportSpecifierInfo.ts
+++ b/src/util/getImportExportSpecifierInfo.ts
@@ -87,0 +88 @@ export default function getImportExportSpecifierInfo(
+export { getImportExportSpecifierInfo as HACK };
--- a/src/util/getJSXPragmaInfo.ts --- a/src/util/getJSXPragmaInfo.ts
+++ b/src/util/getJSXPragmaInfo.ts +++ b/src/util/getJSXPragmaInfo.ts
@@ -14,0 +15 @@ export default function getJSXPragmaInfo(options: Options): JSXPragmaInfo { @@ -14,0 +15 @@ export default function getJSXPragmaInfo(options: Options): JSXPragmaInfo {
+export { getJSXPragmaInfo as HACK }; +export { getJSXPragmaInfo as HACK };
--- a/test/source-maps-test.ts
+++ b/test/source-maps-test.ts
@@ -26,0 +27 @@ var _a = require('./a'); var _a2 = _interopRequireDefault(_a);
+delete result.sourceMap.ignoreList;
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" \
&& workaround src/parser/plugins/typescript.ts\
&& workaround src/transformers/CJSImportTransformer.ts\
&& rm -rf node_modules \ && rm -rf node_modules \
&& npm_install \ && npm_install \
&& npm run clean \ && npm run clean \

View File

@ -25,7 +25,7 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
} while (prev !== stdout); } while (prev !== stdout);
return stdout; return stdout;
} : 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 ([ var stdout = ([
/\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/, /\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/,
/\basync([ \t]+|[ \t]*#)[^\s()[\]{}#:;,.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/, /\basync([ \t]+|[ \t]*#)[^\s()[\]{}#:;,.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
/\basync[ \t]*\*[ \t]*[^\s()[\]{}#:;,.&|!~=*%/+-]+\s*\(/, /\basync[ \t]*\*[ \t]*[^\s()[\]{}#:;,.&|!~=*%/+-]+\s*\(/,
@ -33,11 +33,9 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/, /\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
].some(function(pattern) { ].some(function(pattern) {
return pattern.test(code); return pattern.test(code);
})) { }) ? run_code_exec : run_code_vm)(code, toplevel, timeout);
return run_code_exec(code, toplevel, timeout); var len = typeof stdout == "string" && stdout.length;
} else { return len > 1000 ? stdout.slice(0, 1000) + "…《" + len + "》" : stdout;
return run_code_vm(code, toplevel, timeout);
}
}; };
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) { exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false; if (typeof expected != typeof actual) return false;
@ -51,7 +49,16 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
} : function(expected, actual) { } : function(expected, actual) {
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual); return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
}; };
exports.patch_module_statements = function(code) { exports.patch_module_statements = function(code, module) {
if (module || module === undefined && /\bawait\b/.test(code)) {
code = [
"(async()=>{",
code,
'})().catch(e=>process.on("exit",()=>{throw e}));',
];
if (module) code.unshift('"use strict";');
code = code.join("\n");
}
var count = 0, has_default = "", imports = [], strict_mode = ""; var count = 0, has_default = "", imports = [], strict_mode = "";
code = code.replace(/^\s*("|')use strict\1\s*;?/, function(match) { code = code.replace(/^\s*("|')use strict\1\s*;?/, function(match) {
strict_mode = match; strict_mode = match;
@ -286,6 +293,7 @@ function run_code_exec(code, toplevel, timeout) {
var result = spawnSync(process.argv[0], [ '--max-old-space-size=2048' ], { var result = spawnSync(process.argv[0], [ '--max-old-space-size=2048' ], {
encoding: "utf8", encoding: "utf8",
input: code, input: code,
maxBuffer: 1073741824,
stdio: "pipe", stdio: "pipe",
timeout: timeout || 5000, timeout: timeout || 5000,
}); });

View File

@ -1142,7 +1142,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
} }
case STMT_FUNC_EXPR: case STMT_FUNC_EXPR:
// "In non-strict mode code, functions can only be declared at top level, inside a block, or ..." // "In non-strict mode code, functions can only be declared at top level, inside a block, or ..."
// (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block) // (don't make func decls in `if`; it's only a parser thing because you can't call them without a block)
return "{" + createFunction(recurmax, NO_DEFUN, canThrow, stmtDepth) + "}"; return "{" + createFunction(recurmax, NO_DEFUN, canThrow, stmtDepth) + "}";
case STMT_TRY: case STMT_TRY:
// catch var could cause some problems // catch var could cause some problems
@ -2113,13 +2113,7 @@ if (require.main !== module) {
} }
function run_code(code, toplevel, timeout) { function run_code(code, toplevel, timeout) {
if (async && has_await) code = [ return sandbox.run_code(sandbox.patch_module_statements(code, async && has_await), toplevel, timeout);
'"use strict";',
"(async()=>{",
code,
'})().catch(e=>process.on("exit",()=>{throw e}));',
].join("\n");
return sandbox.run_code(sandbox.patch_module_statements(code), toplevel, timeout);
} }
function writeln(stream, msg) { function writeln(stream, msg) {
@ -2139,7 +2133,7 @@ function errorln(msg) {
function try_beautify(code, toplevel, result, printfn, options) { function try_beautify(code, toplevel, result, printfn, options) {
var o = JSON.parse(beautify_options); var o = JSON.parse(beautify_options);
if (async && has_await) o.module = true; o.module = !!(async && has_await);
var beautified = UglifyJS.minify(code, o); var beautified = UglifyJS.minify(code, o);
if (beautified.error) { if (beautified.error) {
printfn("// !!! beautify failed !!!"); printfn("// !!! beautify failed !!!");
@ -2268,6 +2262,7 @@ function log(options) {
var reduce_options = JSON.parse(options); var reduce_options = JSON.parse(options);
reduce_options.validate = true; reduce_options.validate = true;
var reduced = reduce_test(original_code, reduce_options, { var reduced = reduce_test(original_code, reduce_options, {
max_timeout: max_timeout,
verbose: false, verbose: false,
}).code; }).code;
if (reduced) { if (reduced) {
@ -2529,6 +2524,7 @@ beautify_options = JSON.stringify(beautify_options);
minify_options = minify_options.map(JSON.stringify); minify_options = minify_options.map(JSON.stringify);
var original_code, original_result, original_erred; var original_code, original_result, original_erred;
var uglify_code, uglify_result, ok; var uglify_code, uglify_result, ok;
var max_timeout = 10000;
for (var round = 1; round <= num_iterations; round++) { for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r"); process.stdout.write(round + " of " + num_iterations + "\r");
@ -2546,13 +2542,19 @@ for (var round = 1; round <= num_iterations; round++) {
println("original result:"); println("original result:");
println(result); println(result);
println(); println();
// ignore v8 parser bug if (is_error_timeout(result)) orig_result[toplevel] = result = run_code(original_code, toplevel, max_timeout);
return bug_async_arrow_rest(result) // skip over test cases which take too long to run
// ignore Node.js `__proto__` quirks if (is_error_timeout(result)) return true;
|| bug_proto_stream(result) // ignore v8 parser bug
// ignore runtime platform bugs if (bug_async_arrow_rest(result)) return true;
|| result.message == "Script execution aborted."; // ignore Node.js `__proto__` quirks
})) continue; if (bug_proto_stream(result)) return true;
// ignore runtime platform bugs
if (result.message == "Script execution aborted.") return true;
})) {
num_iterations++;
continue;
}
minify_options.forEach(function(options) { minify_options.forEach(function(options) {
var o = JSON.parse(options); var o = JSON.parse(options);
if (async && has_await) { if (async && has_await) {
@ -2575,22 +2577,10 @@ for (var round = 1; round <= num_iterations; round++) {
if (!ok && uglify_erred && bug_proto_stream(uglify_result)) ok = true; if (!ok && uglify_erred && bug_proto_stream(uglify_result)) ok = true;
// ignore runtime platform bugs // ignore runtime platform bugs
if (!ok && uglify_erred && uglify_result.message == "Script execution aborted.") ok = true; if (!ok && uglify_erred && uglify_result.message == "Script execution aborted.") ok = true;
// handle difference caused by time-outs // ignore spurious time-outs
if (!ok) { if (!ok && uglify_erred && is_error_timeout(uglify_result)) {
if (original_erred && is_error_timeout(original_result)) { var waited_result = run_code(uglify_code, toplevel, max_timeout);
if (uglify_erred && is_error_timeout(uglify_result)) { ok = sandbox.same_stdout(original_result, waited_result);
// ignore difference in error message
ok = true;
} else {
// ignore spurious time-outs
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = run_code(original_code, toplevel, 10000);
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
}
} else if (uglify_erred && is_error_timeout(uglify_result)) {
// ignore spurious time-outs
var waited_result = run_code(uglify_code, toplevel, 10000);
ok = sandbox.same_stdout(original_result, waited_result);
}
} }
// ignore declaration order of global variables // ignore declaration order of global variables
if (!ok && !toplevel) { if (!ok && !toplevel) {

View File

@ -2,6 +2,7 @@
{ {
"compress": false, "compress": false,
"mangle": false, "mangle": false,
"module": false,
"output": { "output": {
"beautify": true, "beautify": true,
"braces": true "braces": true
@ -9,14 +10,19 @@
"rename": true "rename": true
}, },
{ {
"compress": false "compress": false,
"module": false
}, },
{ {
"mangle": false "mangle": false,
"module": false
},
{
"module": false
}, },
{},
{ {
"ie": true, "ie": true,
"module": false,
"toplevel": true "toplevel": true
}, },
{ {
@ -28,6 +34,7 @@
}, },
"keep_fargs": true, "keep_fargs": true,
"keep_fnames": true, "keep_fnames": true,
"module": false,
"toplevel": true "toplevel": true
}, },
{ {
@ -39,6 +46,7 @@
"unsafe_math": true, "unsafe_math": true,
"unsafe_proto": true, "unsafe_proto": true,
"unsafe_regexp": true "unsafe_regexp": true
} },
"module": false
} }
] ]

View File

@ -4323,6 +4323,7 @@
"enable", "enable",
"enableBackground", "enableBackground",
"enableDelegations", "enableDelegations",
"enableHighAccuracy",
"enableStyleSheetsForSet", "enableStyleSheetsForSet",
"enableVertexAttribArray", "enableVertexAttribArray",
"enabled", "enabled",
@ -5553,6 +5554,7 @@
"maxWidth", "maxWidth",
"maxZoom", "maxZoom",
"maximize", "maximize",
"maximumAge",
"maximumFractionDigits", "maximumFractionDigits",
"measure", "measure",
"measureText", "measureText",

View File

@ -15,13 +15,13 @@ exports.FILES = [
require.resolve("./exports.js"), require.resolve("./exports.js"),
]; ];
new Function("exports", function() { new Function("domprops", "exports", function() {
var code = exports.FILES.map(function(file) { var code = exports.FILES.map(function(file) {
return fs.readFileSync(file, "utf8"); return fs.readFileSync(file, "utf8");
}); });
code.push("exports.describe_ast = " + describe_ast.toString()); code.push("exports.describe_ast = " + describe_ast.toString());
return code.join("\n\n"); return code.join("\n\n");
}())(exports); }())(require("./domprops.json"), exports);
function to_comment(value) { function to_comment(value) {
if (typeof value != "string") value = JSON.stringify(value, function(key, value) { if (typeof value != "string") value = JSON.stringify(value, function(key, value) {
@ -100,7 +100,7 @@ function infer_options(options) {
exports.default_options = function() { exports.default_options = function() {
var defs = infer_options({ 0: 0 }); var defs = infer_options({ 0: 0 });
Object.keys(defs).forEach(function(component) { Object.keys(defs).forEach(function(component) {
var options = {}; var options = { module: false };
options[component] = { 0: 0 }; options[component] = { 0: 0 };
if (options = infer_options(options)) { if (options = infer_options(options)) {
defs[component] = options; defs[component] = options;

View File

@ -6,7 +6,7 @@ try {
} catch (e) { } catch (e) {
// ensure output buffers are flushed before process termination // ensure output buffers are flushed before process termination
var exit = process.exit; var exit = process.exit;
process.exit = function() { if ("bufferSize" in process.stdout) process.exit = function() {
var args = [].slice.call(arguments); var args = [].slice.call(arguments);
process.once("uncaughtException", function() { process.once("uncaughtException", function() {
(function callback() { (function callback() {