Compare commits

...

164 Commits

Author SHA1 Message Date
Alex Lam S.L
4a1da492dd v3.17.3 2022-10-06 02:14:42 +08:00
Alex Lam S.L
94a954c3d1 minor clean-ups (#5701) 2022-10-06 02:06:21 +08:00
Alex Lam S.L
be8ccc3ab5 fix corner case in varify (#5698)
fixes #5697
2022-10-04 16:03:24 +08:00
Alex Lam S.L
58d997a3d6 fix corner case in booleans & conditionals (#5696) 2022-10-04 12:58:55 +08:00
Alex Lam S.L
dabcc39b51 fix corner cases in booleans & conditionals (#5695)
fixes #5694
2022-10-03 22:47:15 +08:00
Alex Lam S.L
140e4e0da8 fix corner case in inline (#5693)
fixes #5692
2022-10-03 08:01:56 +08:00
Alex Lam S.L
80fc862547 enhance assignments, booleans & conditionals (#5691) 2022-10-03 08:01:23 +08:00
Alex Lam S.L
6cdc035b2f fix corner case in if_return (#5689)
fixes #5688
2022-09-30 06:49:51 +08:00
Alex Lam S.L
e1e3516397 fix corner case in reduce_vars (#5687) 2022-09-30 02:00:37 +08:00
Alex Lam S.L
bd5fc4cb1b implement mangle.properties.domprops (#5686)
- support destructuring syntax
- fix corner case with comma operator
2022-09-29 12:18:04 +08:00
Alex Lam S.L
a570c00251 fix corner case in conditionals & if_return (#5685)
fixes #5684
2022-09-28 00:04:32 +08:00
Alex Lam S.L
3fa2086681 improve usability of mangle.properties (#5683)
fixes #5682
2022-09-27 13:52:58 +08:00
Alex Lam S.L
8e65413b99 fix corner cases in conditionals & if_return (#5680)
fixes #5679
2022-09-27 01:28:03 +08:00
Alex Lam S.L
8ca40070a4 workaround GitHub Actions quirks (#5678) 2022-09-27 00:16:40 +08:00
Alex Lam S.L
f9b811ce83 v3.17.2 2022-09-26 00:12:51 +08:00
Alex Lam S.L
9ac3879b06 fix corner case in conditionals (#5676) 2022-09-23 11:09:55 +08:00
Alex Lam S.L
37d3e4feaa fix corner case in if_return (#5675) 2022-09-22 23:27:06 +08:00
Alex Lam S.L
43ec350cd2 fix corner case in conditionals (#5674)
fixes #5673
2022-09-22 10:58:44 +08:00
Alex Lam S.L
63b04a687a minor tweaks (#5672) 2022-09-21 23:11:46 +08:00
Alex Lam S.L
9efa02afb6 fix corner case in assignments (#5671)
fixes #5670
2022-09-21 07:56:16 +08:00
Alex Lam S.L
3a6e58109e v3.17.1 2022-09-20 04:13:28 +08:00
Alex Lam S.L
5ac6ec5496 improve usability of --mangle-props (#5669) 2022-09-18 09:37:06 +08:00
Alex Lam S.L
eb22f0101e fix corner case in unused (#5668)
fixes #5663
2022-09-17 13:32:41 +08:00
Alex Lam S.L
e4bff315eb fix corner case in conditionals (#5667)
fixes #5666
2022-09-17 10:42:32 +08:00
Alex Lam S.L
001f6f9719 fix corner case in inline (#5664)
fixes #5662
2022-09-17 08:54:54 +08:00
Alex Lam S.L
e0b302d651 fix corner case in merge_vars (#5661)
fixes #5660
2022-09-14 23:36:54 +08:00
Alex Lam S.L
fa2511f71c tweak ufuzz job scheduling (#5659) 2022-09-11 04:05:21 +08:00
Alex Lam S.L
edf1bf1106 enhance varify (#5658) 2022-09-11 03:28:54 +08:00
Alex Lam S.L
88dfc49683 fix corner case in merge_vars (#5657)
fixes #5656
2022-09-10 04:14:33 +08:00
Alex Lam S.L
9dec612cd5 enhance inline (#5655)
- improve fix for #5653
2022-09-09 04:07:47 +08:00
Alex Lam S.L
02d966d914 fix corner case in hoist_props (#5654)
fixes #5653
2022-09-08 10:55:59 +08:00
Alex Lam S.L
5b5f6e329c fix corner case in ie (#5652)
fixes #5651
2022-09-08 10:49:40 +08:00
Alex Lam S.L
4e4a2f8ed3 fix corner case in if_return (#5650)
fixes #5649
2022-09-08 10:49:05 +08:00
Alex Lam S.L
32bd65a87f support ExtendScript parser quirks (#5648)
closes #1144
2022-09-07 02:28:34 +08:00
Alex Lam S.L
318206d41d suppress false positives in ufuzz (#5647) 2022-09-06 01:33:22 +08:00
Alex Lam S.L
535212c69e allow glob-style input for --in-situ (#5646)
closes #5645
2022-09-05 22:54:35 +08:00
Alex Lam S.L
1d42e9ad55 fix corner case in collapse_vars (#5644)
fixes #5643
2022-09-04 10:10:31 +08:00
Alex Lam S.L
78f354beb8 fix corner case in dead_code (#5642)
fixes #5641
2022-09-04 06:18:25 +08:00
Alex Lam S.L
e012f046bc tweak test cases (#5640) 2022-08-31 12:16:42 +08:00
Alex Lam S.L
f63b7b079d fix corner case in collapse_vars (#5639)
fixes #5638
2022-08-31 08:44:04 +08:00
Alex Lam S.L
d530f9332c enhance awaits (#5637) 2022-08-31 02:51:42 +08:00
Alex Lam S.L
10bc86ba10 enhance reduce_vars (#5636) 2022-08-30 16:00:43 +08:00
Alex Lam S.L
15b608f74c fix corner case in inline (#5635)
fixes #5634
2022-08-30 00:45:35 +08:00
Alex Lam S.L
7c52af0dec workaround quirks from npm (#5633) 2022-08-26 20:08:04 +08:00
Alex Lam S.L
cd97237c59 workaround quirks from GitHub Actions (#5632) 2022-08-26 15:16:03 +08:00
Alex Lam S.L
965e9767e5 workaround quirks from Node.js (#5631) 2022-08-26 06:25:44 +08:00
Alex Lam S.L
41a7000745 workaround quirks from GitHub Actions (#5630) 2022-08-26 02:35:53 +08:00
Alex Lam S.L
9cdc1ef6c2 fix corner case in unused (#5629)
fixes #5628
2022-08-25 05:01:12 +08:00
Alex Lam S.L
4db81065ee fix corner case in hoist_vars (#5627)
fixes #5626
2022-08-24 00:19:47 +08:00
Alex Lam S.L
4653e8aec0 improve diagnostics on top_retain & mangle.properties (#5622)
closes #5618
2022-08-19 02:32:21 +08:00
Alex Lam S.L
ac002b6338 fix corner case in reduce_vars (#5624)
fixes #5623
2022-08-19 02:31:48 +08:00
Alex Lam S.L
9eea3a673a provide diagnostic details on --mangle-props (#5621)
closes #5618
2022-08-17 22:22:30 +08:00
Alex Lam S.L
d6d2f5ced2 enhance reduce_vars (#5616)
closes #5614
2022-08-17 09:25:59 +08:00
Alex Lam S.L
887e086890 fix corner case in if_return (#5620)
fixes #5619
2022-08-17 09:10:33 +08:00
Alex Lam S.L
8602d1ba17 v3.17.0 2022-08-17 03:45:32 +08:00
Alex Lam S.L
dd90135944 fix corner case in pure_getters (#5617) 2022-08-14 02:54:06 +08:00
Alex Lam S.L
612701a706 tweak ufuzz test case generation (#5615) 2022-08-12 03:55:54 +08:00
Alex Lam S.L
503532cf77 workaround sporadic I/O lags in GitHub Actions (#5613) 2022-08-10 07:36:14 +08:00
Alex Lam S.L
6c0e522922 workaround sporadic I/O lags in GitHub Actions (#5612) 2022-08-10 04:33:32 +08:00
Alex Lam S.L
9d37276986 tweak ufuzz test case generation (#5611) 2022-08-10 00:20:20 +08:00
Alex Lam S.L
5a4cd09938 enhance inline (#5610) 2022-08-09 22:54:29 +08:00
Alex Lam S.L
c32fe26b8d fix corner case in merge_vars (#5609) 2022-08-09 10:18:11 +08:00
Alex Lam S.L
2c3c4ec323 improve source mapping accuracy (#5608) 2022-08-09 02:02:43 +08:00
Alex Lam S.L
f451a7ad79 implement --expression (#5607) 2022-08-08 03:42:18 +08:00
Alex Lam S.L
07953b36b0 update dependencies (#5605) 2022-08-06 13:16:47 +08:00
Alex Lam S.L
387c69b194 minor clean-ups (#5604) 2022-08-06 10:45:44 +08:00
Alex Lam S.L
a9d9af53e9 fix corner case in if_return (#5603)
fixes #5602
2022-08-06 07:56:20 +08:00
Alex Lam S.L
8a07f1202c expand builtins exclusions (#5601)
closes #5600
2022-08-05 13:37:02 +08:00
Alex Lam S.L
41b65af6e2 fix corner cases with static modifier (#5599) 2022-08-05 02:48:21 +08:00
Alex Lam S.L
884842cd6c fix corner case in if_return (#5598)
fixes #5597
2022-08-04 06:50:51 +08:00
Alex Lam S.L
8076d66ae5 fix corner case in if_return (#5596)
fixes #5595
2022-08-03 20:07:55 +08:00
Alex Lam S.L
64e3ceec3b enhance if_return (#5594) 2022-08-03 07:37:31 +08:00
Alex Lam S.L
672cdfa57a enhance conditionals (#5593) 2022-08-02 19:01:57 +08:00
Alex Lam S.L
e39f33e41b fix corner cases in if_return (#5590)
fixes #5589
fixes #5591
fixes #5592
2022-07-31 02:45:52 +08:00
Alex Lam S.L
6667440aaf enhance if_return (#5588)
fixes #5587
2022-07-30 20:53:46 +08:00
Alex Lam S.L
ab5c7e6863 fix corner cases in if_return (#5585)
fixes #5583
fixes #5584
fixes #5586
2022-07-30 16:07:19 +08:00
Alex Lam S.L
08c386f363 enhance if_return (#5582) 2022-07-30 05:25:17 +08:00
Alex Lam S.L
937a672879 fix corner case in mangle (#5581)
fixes #5580
2022-07-29 03:04:10 +08:00
Alex Lam S.L
513995f57d fix corner case in inline & reduce_vars (#5579) 2022-07-28 23:53:11 +08:00
Alex Lam S.L
db6fd6db3e enhance side_effects (#5578) 2022-07-28 04:06:11 +08:00
Alex Lam S.L
da930affd2 fix corner case in inline (#5577)
fixes #5576
2022-07-26 10:46:54 +08:00
Alex Lam S.L
996836b67e enhance conditionals (#5575) 2022-07-26 01:49:45 +08:00
Alex Lam S.L
fc7678c115 v3.16.3 2022-07-25 06:08:04 +08:00
Alex Lam S.L
b371dc2d1e fix corner case in collapse_vars (#5574)
fixes #5573
2022-07-23 07:18:26 +08:00
Alex Lam S.L
56e9454f1f fix corner case with spread syntax (#5572) 2022-07-23 03:07:04 +08:00
Alex Lam S.L
d67daa8314 support string namespace in import & export (#5570) 2022-07-20 05:55:38 +08:00
Alex Lam S.L
f0120e90b6 fix corner case collapse_vars (#5569)
fixes #5568
2022-07-18 09:04:51 +08:00
Alex Lam S.L
ec4558be29 fix corner cases with parameter scope (#5567)
fixes #5566
2022-07-17 16:03:12 +08:00
Alex Lam S.L
685ab357cc document v8 quirks (#5565)
closes #5564
2022-07-17 00:22:16 +08:00
Alex Lam S.L
5792f30175 fix corner case in evaluate (#5559)
fixes #5558
2022-07-15 20:36:52 +08:00
Alex Lam S.L
24443b6764 enhance collapse_vars (#5556) 2022-07-12 23:49:43 +08:00
Alex Lam S.L
154edf0427 enhance collapse_vars (#5555) 2022-07-11 23:10:40 +08:00
Alex Lam S.L
4778cf88e2 upgrade AST<->ESTree translation (#5554) 2022-07-11 07:18:25 +08:00
Alex Lam S.L
38bd4f65d0 fix corner cases in collapse_vars (#5553)
fixes #5552
2022-07-09 20:50:54 +08:00
Alex Lam S.L
0b808f6428 parse import expressions correctly (#5551)
fixes #5550
2022-07-08 19:25:30 +08:00
Alex Lam S.L
b2bc2e1173 parse export & import statements correctly (#5550)
fixes #5548
2022-07-08 04:04:56 +08:00
Alex Lam S.L
80787ff7ef minor cleanups (#5549) 2022-07-08 03:14:54 +08:00
Alex Lam S.L
b92a89f325 fix corner case in conditionals (#5548) 2022-07-07 21:28:33 +08:00
Alex Lam S.L
902292f776 fix corner case in conditionals (#5547)
fixes #5546
2022-07-07 15:49:33 +08:00
Alex Lam S.L
3dcf098468 fix corner cases in conditionals & switches (#5545)
fixes #5543
fixes #5544
2022-07-07 14:59:06 +08:00
Alex Lam S.L
d89f0965aa enhance conditionals (#5542) 2022-07-07 12:17:23 +08:00
Alex Lam S.L
c8d98f4787 enhance if_return (#5541) 2022-07-07 04:28:00 +08:00
Alex Lam S.L
0207b46d70 enhance if_return & inline (#5538) 2022-07-06 11:40:07 +08:00
Alex Lam S.L
aa2a9fbedb v3.16.2 2022-07-04 08:50:56 +08:00
Alex Lam S.L
3596b4feda fix corner case in inline (#5537)
fixes #5536
2022-07-02 00:10:02 +08:00
Alex Lam S.L
51deeff72e enhance inline (#5535) 2022-07-01 11:24:16 +08:00
Alex Lam S.L
4c227cc6bd fix corner cases in inline & unused (#5534)
fixes #5533
2022-06-30 15:34:45 +08:00
Alex Lam S.L
2426657daa fix corner case in inline (#5532)
fixes #5531
2022-06-30 04:09:53 +08:00
Alex Lam S.L
e1b03d0235 fix corner case in inline (#5529)
fixes #5528
2022-06-29 07:37:58 +08:00
Alex Lam S.L
f1b3e9df1e fix corner case in inline (#5527)
fixes #5526
2022-06-26 20:48:14 +08:00
Alex Lam S.L
fcc87edb71 fix corner cases in dead_code & if_return (#5525)
fixes #5521
fixes #5522
fixes #5523
fixes #5524
2022-06-26 18:40:56 +08:00
Alex Lam S.L
8b464331ba enhance dead_code & if_return (#5520) 2022-06-26 12:32:25 +08:00
Alex Lam S.L
9f57920566 enhance if_return (#5518) 2022-06-24 00:52:22 +08:00
Alex Lam S.L
933ca9ddd8 fix corner case in reduce_vars (#5517)
fixes #5516
2022-06-19 03:27:00 +08:00
Alex Lam S.L
74e36e4456 v3.16.1 2022-06-17 07:53:29 +08:00
Alex Lam S.L
4382bfe848 fix corner case in collapse_vars (#5513)
fixes #5512
2022-06-13 07:55:15 +08:00
Alex Lam S.L
b6f250f5c9 enhance unused (#5511) 2022-06-12 21:24:42 +08:00
Alex Lam S.L
5d69545299 enhance unsafe_comps (#5510) 2022-06-12 12:15:43 +08:00
Alex Lam S.L
139fad0c05 fix corner cases with instanceof (#5509)
- enhance `evaluate`
2022-06-12 10:01:54 +08:00
Alex Lam S.L
99946a3993 fix corner case in dead_code (#5507)
fixes #5506
2022-06-12 05:26:51 +08:00
Alex Lam S.L
053cb27fe3 fix corner case in collapse_vars (#5505)
fixes #5504
2022-06-10 09:12:59 +08:00
Alex Lam S.L
25017978e7 fix corner case in collapse_vars (#5503)
fixes #5502
2022-06-10 02:07:07 +08:00
Alex Lam S.L
f749863cb2 document ECMAScript quirks (#5501)
closes #5500
2022-06-09 03:01:00 +08:00
Alex Lam S.L
123f9cf987 fix corner case in hoist_props (#5499)
fixes #5498
2022-06-07 23:29:42 +08:00
Alex Lam S.L
a758b40e3f suppress false positives in ufuzz (#5497) 2022-06-07 23:28:06 +08:00
Alex Lam S.L
44e5e99aae parse directives within arrow functions correctly (#5496)
fixes #5495
2022-06-07 10:33:17 +08:00
Alex Lam S.L
be53c4838b fix corner case in collapse_vars (#5494)
fixes #5493
2022-06-06 23:36:19 +08:00
Alex Lam S.L
0c7b016fa7 fix corner case in inline & module (#5492)
fixes #5491
2022-06-06 22:52:22 +08:00
Alex Lam S.L
00665766da fix corner case in side_effects (#5490)
fixes #5489
2022-06-06 20:32:32 +08:00
Alex Lam S.L
88b4283200 support class static initialization block (#5488) 2022-06-06 12:01:15 +08:00
Alex Lam S.L
d2bd0d1c1c support top-level await (#5487) 2022-06-06 11:52:01 +08:00
Alex Lam S.L
25441d44f6 v3.16.0 2022-06-06 11:29:26 +08:00
Alex Lam S.L
a025392a30 fix corner case in comparisons (#5486)
fixes #5485
2022-06-05 00:47:38 +08:00
Alex Lam S.L
ad5f5ef2a3 fix corner case in webkit (#5483)
fixes #5480
2022-06-02 02:45:02 +08:00
Chen Yangjian
40e669eacb docs: toplevel webkit option sets compress.webkit as well (#5480) 2022-06-02 02:44:06 +08:00
Alex Lam S.L
ad3a331ca3 fix corner case in collapse_vars (#5482)
fixes #5481
2022-06-02 02:42:39 +08:00
Alex Lam S.L
3c9e1693d5 fix corner case in side_effects (#5479)
fixes #5478
2022-05-31 00:27:40 +08:00
Alex Lam S.L
8bc03dc6c4 fix corner case in keep_fargs (#5477)
fixes #5476
2022-05-29 12:10:19 +08:00
Alex Lam S.L
2152f00de2 enhance inline & module (#5475) 2022-05-27 11:57:05 +08:00
Alex Lam S.L
94aae05d45 fix corner case in merge_vars (#5472)
fixes #5471
2022-05-27 03:13:24 +08:00
Alex Lam S.L
0dbf2b1d3c suppress false positives in ufuzz (#5473) 2022-05-26 23:17:47 +08:00
Alex Lam S.L
59b23b8c13 fix corner case in booleans (#5470)
fixes #5469
2022-05-26 05:33:50 +08:00
Alex Lam S.L
5979b195fe suppress false positives in ufuzz (#5468) 2022-05-25 23:50:47 +08:00
Alex Lam S.L
a1cff23377 suppress false positives in ufuzz (#5467) 2022-05-25 06:35:59 +08:00
Alex Lam S.L
c82fc1ef71 implement --module (#5462) 2022-05-24 05:45:47 +08:00
Alex Lam S.L
740f93f5a9 fix corner case in merge_vars (#5466)
fixes #5465
2022-05-24 05:45:07 +08:00
Alex Lam S.L
d4caa97b88 fix corner case in reduce_vars (#5464)
fixes #5463
2022-05-23 11:08:12 +08:00
Alex Lam S.L
c2ca7b7659 drop unused extends properly (#5461) 2022-05-23 03:53:32 +08:00
Alex Lam S.L
59edda6ca5 suppress false positives in ufuzz (#5460) 2022-05-22 01:36:45 +08:00
Alex Lam S.L
1668bc33c3 improve ufuzz coverage (#5459) 2022-05-21 02:57:13 +08:00
Alex Lam S.L
01f1e3fef8 avoid v8 quirks in ufuzz (#5458) 2022-05-20 00:00:24 +08:00
Alex Lam S.L
27aa85f84b fix corner cases in merge_vars (#5457)
fixes #5456
2022-05-19 06:39:20 +08:00
Alex Lam S.L
33c9c48318 fix corner case in hoist_props & unused (#5455)
fixes #5454
2022-05-19 04:45:38 +08:00
Alex Lam S.L
63f16e4616 fix corner case in merge_vars (#5452)
fixes #5451
2022-05-18 02:41:05 +08:00
Alex Lam S.L
cb6dd34b98 avoid broken versions of Node.js (#5453) 2022-05-18 02:40:31 +08:00
Alex Lam S.L
27727e6926 fix corner cases in unused (#5449)
fixes #5448
2022-05-17 17:03:06 +08:00
Alex Lam S.L
a968ddc78c avoid webpack bug in web-tooling-benchmark (#5450) 2022-05-17 14:08:11 +08:00
Alex Lam S.L
f70462aeb2 fix corner case in merge_vars (#5445)
fixes #5444
2022-05-16 16:30:14 +08:00
Alex Lam S.L
3aa92c76cc avoid extends error in ufuzz (#5447) 2022-05-16 11:11:10 +08:00
Alex Lam S.L
fc6a66836a fix corner case in unused (#5446)
fixes #5444
2022-05-16 09:13:30 +08:00
Alex Lam S.L
31167da1a9 avoid extends error in test cases (#5443) 2022-05-16 06:50:22 +08:00
Alex Lam S.L
7db2ada880 fix corner case in hoist_props (#5442)
fixes #5441
2022-05-16 06:49:09 +08:00
Alex Lam S.L
e31bbe329a improve compatibility with use strict (#5440) 2022-05-14 12:15:54 +08:00
Alex Lam S.L
8946c87011 suppress invalid test case generation (#5439)
- document v8 quirks

closes #5438
2022-05-12 04:38:11 +08:00
94 changed files with 13474 additions and 2114 deletions

View File

@@ -50,7 +50,7 @@ jobs:
OPTIONS: ${{ matrix.options }}
SCRIPT: ${{ matrix.script }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Perform uglify, build & test
shell: bash
run: |

View File

@@ -15,9 +15,10 @@ jobs:
env:
NODE: ${{ matrix.node }}
TYPE: ${{ matrix.script }}
UGLIFY_GITHUB_LAG: 10000
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: tmp
key: tmp ${{ matrix.script }}

View File

@@ -17,13 +17,13 @@ jobs:
fail-fast: false
matrix:
include:
- node: latest
- node: '16'
os: macos-latest
- node: '8'
- node: '12'
os: ubuntu-latest
- node: '8'
os: ubuntu-latest
- node: '8'
- node: '12'
os: windows-latest
- node: '8'
os: windows-latest
@@ -32,7 +32,7 @@ jobs:
env:
NODE: ${{ matrix.node }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Perform fuzzing
shell: bash
run: |

View File

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

119
README.md
View File

@@ -54,8 +54,6 @@ a double dash to prevent input files being used as option arguments:
modules and Userscripts that may
be anonymous function wrapped (IIFE)
by the .user.js engine `caller`.
`expression` Parse a single expression, rather than
a program (for parsing JSON).
`spidermonkey` Assume input files are SpiderMonkey
AST format (as JSON).
-c, --compress [options] Enable compressor/specify compressor options:
@@ -111,6 +109,8 @@ a double dash to prevent input files being used as option arguments:
-d, --define <expr>[=value] Global definitions.
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
argument(s) & value(s).
--expression Parse a single expression, rather than a program
(for parsing JSON).
--ie Support non-standard Internet Explorer.
Equivalent to setting `ie: true` in `minify()`
for `compress`, `mangle` and `output` options.
@@ -118,6 +118,7 @@ a double dash to prevent input files being used as option arguments:
--keep-fargs Do not mangle/drop function arguments.
--keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name.
--module Process input as ES module (implies --toplevel)
--name-cache <file> File to hold mangled name mappings.
--self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options:
@@ -146,7 +147,7 @@ a double dash to prevent input files being used as option arguments:
--warn Print warning messages.
--webkit Support non-standard Safari/Webkit.
Equivalent to setting `webkit: true` in `minify()`
for `mangle` and `output` options.
for `compress`, `mangle` and `output` options.
By default UglifyJS will not try to be Safari-proof.
--wrap <name> Embed everything in a big function, making the
“exports” and “global” variables available. You
@@ -326,7 +327,7 @@ unquoted style (`o.foo`). Example:
// stuff.js
var o = {
"foo": 1,
bar: 3
bar: 3,
};
o.foo += o.bar;
console.log(o.foo);
@@ -338,6 +339,16 @@ $ uglifyjs stuff.js --mangle-props keep_quoted -c -m
var o={foo:1,o:3};o.foo+=o.o,console.log(o.foo);
```
If the minified output will be processed again by UglifyJS, consider specifying
`keep_quoted_props` so the same property names are preserved:
```bash
$ uglifyjs stuff.js --mangle-props keep_quoted -c -m -O keep_quoted_props
```
```javascript
var o={"foo":1,o:3};o.foo+=o.o,console.log(o.foo);
```
### Debugging property name mangling
You can also pass `--mangle-props debug` in order to mangle property names
@@ -503,6 +514,8 @@ if (result.error) throw result.error;
- `compress` (default: `{}`) — pass `false` to skip compressing entirely.
Pass an object to specify custom [compress options](#compress-options).
- `expression` (default: `false`) — parse as a single expression, e.g. JSON.
- `ie` (default: `false`) — enable workarounds for Internet Explorer bugs.
- `keep_fargs` (default: `false`) — pass `true` to prevent discarding or mangling
@@ -517,6 +530,10 @@ if (result.error) throw result.error;
- `mangle.properties` (default: `false`) — a subcategory of the mangle option.
Pass an object to specify custom [mangle property options](#mangle-properties-options).
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` and support for top-level `await`,
alongside with `toplevel` enabled.
- `nameCache` (default: `null`) — pass an empty object `{}` or a previously
used `nameCache` object if you wish to cache mangled variable and
property names across multiple invocations of `minify()`. Note: this is
@@ -628,7 +645,11 @@ to be `false` and all symbol names will be omitted.
- `bare_returns` (default: `false`) — support top level `return` statements
- `html5_comments` (default: `true`)
- `html5_comments` (default: `true`) — process HTML comment as workaround for
browsers which do not recognize `<script>` tags
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` and support for top-level `await`.
- `shebang` (default: `true`) — support `#!command` as the first line
@@ -728,8 +749,11 @@ to be `false` and all symbol names will be omitted.
- `merge_vars` (default: `true`) — combine and reuse variables.
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the
where the return value is discarded, to avoid the parentheses that the
code generator would insert.
- `objects` (default: `true`) — compact duplicate keys in object literals.
@@ -804,8 +828,9 @@ to be `false` and all symbol names will be omitted.
- `unsafe` (default: `false`) — apply "unsafe" transformations (discussion below)
- `unsafe_comps` (default: `false`) — compress expressions like `a <= b` assuming
none of the operands can be (coerced to) `NaN`.
- `unsafe_comps` (default: `false`) — assume operands cannot be (coerced to) `NaN`
in numeric comparisons, e.g. `a <= b`. In addition, expressions involving `in`
or `instanceof` would never throw.
- `unsafe_Function` (default: `false`) — compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
@@ -826,7 +851,7 @@ to be `false` and all symbol names will be omitted.
- `unused` (default: `true`) — drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`)
- `varify` (default: `true`) — convert block-scoped declaractions into `var`
- `varify` (default: `true`) — convert block-scoped declarations into `var`
whenever safe to do so
- `yields` (default: `true`) — apply optimizations to `yield` expressions
@@ -866,12 +891,15 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
### Mangle properties options
- `builtins` (default: `false`) — Use `true` to allow the mangling of builtin
DOM properties. Not recommended to override this setting.
- `builtins` (default: `false`) — Use `true` to allow the mangling of built-in
properties of JavaScript API. Not recommended to override this setting.
- `debug` (default: `false`) — Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `domprops` (default: `false`) — Use `true` to allow the mangling of properties
commonly found in Document Object Model. Not recommended to override this setting.
- `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function
arguments.
@@ -915,6 +943,9 @@ can pass additional arguments that control the code output:
}
```
- `extendscript` (default: `false`) — enable workarounds for Adobe ExtendScript
bugs
- `galio` (default: `false`) — enable workarounds for ANT Galio bugs
- `indent_level` (default: `4`) — indent by specified number of spaces or the
@@ -1331,11 +1362,9 @@ To allow for better optimizations, the compiler makes various assumptions:
- Later versions of JavaScript will throw `SyntaxError` with the following:
```javascript
var await;
async function f() {
class A {
static p = await;
}
}
// SyntaxError: Unexpected reserved word
```
UglifyJS may modify the input which in turn may suppress those errors.
@@ -1346,7 +1375,7 @@ To allow for better optimizations, the compiler makes various assumptions:
// SyntaxError: The left-hand side of a for-of loop may not be 'async'.
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of Chrome and Node.js will give incorrect results with the
- Some versions of Chrome and Node.js will give incorrect results with the
following:
```javascript
console.log({
@@ -1355,9 +1384,15 @@ To allow for better optimizations, the compiler makes various assumptions:
return "FAIL";
},
[42]: "PASS",
}[42], {
...console,
get 42() {
return "FAIL";
},
42: "PASS",
}[42]);
// Expected: "PASS"
// Actual: "FAIL"
// Expected: "PASS PASS"
// Actual: "PASS FAIL"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Earlier versions of JavaScript will throw `TypeError` with the following:
@@ -1389,3 +1424,55 @@ To allow for better optimizations, the compiler makes various assumptions:
// Actual: "FAIL"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Some versions of Chrome and Node.js will give incorrect results with the
following:
```javascript
(async function(a) {
(function() {
var b = await => console.log("PASS");
b();
})();
})().catch(console.error);
// Expected: "PASS"
// Actual: SyntaxError: Unexpected reserved word
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of Chrome and Node.js will give incorrect results with the
following:
```javascript
try {
f();
function f() {
throw 42;
}
} catch (e) {
console.log(typeof f, e);
}
// Expected: "function 42"
// Actual: "undefined 42"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of JavaScript will throw `SyntaxError` with the following:
```javascript
"use strict";
console.log(function f() {
return f = "PASS";
}());
// Expected: "PASS"
// Actual: TypeError: invalid assignment to const 'f'
```
UglifyJS may modify the input which in turn may suppress those errors.
- Adobe ExtendScript will give incorrect results with the following:
```javascript
alert(true ? "PASS" : false ? "FAIL" : null);
// Expected: "PASS"
// Actual: "FAIL"
```
UglifyJS may modify the input which in turn may suppress those errors.
- Adobe ExtendScript will give incorrect results with the following:
```javascript
alert(42 ? null ? "FAIL" : "PASS" : "FAIL");
// Expected: "PASS"
// Actual: SyntaxError: Expected: :
```
UglifyJS may modify the input which in turn may suppress those errors.

View File

@@ -104,9 +104,11 @@ function process_option(name, no_value) {
" --config-file <file> Read minify() options from JSON file.",
" -d, --define <expr>[=value] Global definitions.",
" -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).",
" --expression Parse a single expression, rather than a program.",
" --ie Support non-standard Internet Explorer.",
" --keep-fargs Do not mangle/drop function arguments.",
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
" --module Process input as ES module (implies --toplevel)",
" --name-cache <file> File to hold mangled name mappings.",
" --rename Force symbol expansion.",
" --no-rename Disable symbol expansion.",
@@ -150,8 +152,10 @@ function process_option(name, no_value) {
options[name] = read_value();
break;
case "annotations":
case "expression":
case "ie":
case "ie8":
case "module":
case "timings":
case "toplevel":
case "v8":
@@ -234,17 +238,6 @@ if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot
[ "compress", "mangle" ].forEach(function(name) {
if (!(name in options)) options[name] = false;
});
if (options.mangle && options.mangle.properties) {
if (options.mangle.properties.domprops) {
delete options.mangle.properties.domprops;
} else {
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS.push_uniq(options.mangle.properties.reserved, name);
});
}
}
if (/^ast|spidermonkey$/.test(output)) {
if (typeof options.output != "object") options.output = {};
options.output.ast = true;
@@ -274,6 +267,8 @@ if (specified["self"]) {
if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
if (!options.wrap) options.wrap = "UglifyJS";
paths = UglifyJS.FILES;
} else if (paths.length) {
paths = simple_glob(paths);
}
if (specified["in-situ"]) {
if (output && output != "spidermonkey" || specified["reduce-test"] || specified["self"]) {
@@ -288,7 +283,7 @@ if (specified["in-situ"]) {
run();
});
} else if (paths.length) {
simple_glob(paths).forEach(function(name) {
paths.forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
@@ -487,16 +482,20 @@ function fatal(message) {
// A file glob function that only supports "*" and "?" wildcards in the basename.
// Example: "foo/bar/*baz??.*.js"
// Argument `glob` may be a string or an array of strings.
// Argument `paths` must be an array of strings.
// Returns an array of strings. Garbage in, garbage out.
function simple_glob(glob) {
if (Array.isArray(glob)) {
return [].concat.apply([], glob.map(simple_glob));
}
if (glob.match(/\*|\?/)) {
function simple_glob(paths) {
return paths.reduce(function(paths, glob) {
if (/\*|\?/.test(glob)) {
var dir = path.dirname(glob);
try {
var entries = fs.readdirSync(dir);
var entries = fs.readdirSync(dir).filter(function(name) {
try {
return fs.statSync(path.join(dir, name)).isFile();
} catch (ex) {
return false;
}
});
} catch (ex) {}
if (entries) {
var pattern = "^" + path.basename(glob)
@@ -505,15 +504,20 @@ function simple_glob(glob) {
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.sort().filter(function(name) {
var results = entries.filter(function(name) {
return rx.test(name);
}).map(function(name) {
}).sort().map(function(name) {
return path.join(dir, name);
});
if (results.length) return results;
if (results.length) {
[].push.apply(paths, results);
return paths;
}
}
return [ glob ];
}
paths.push(glob);
return paths;
}, []);
}
function read_file(path, default_value) {

View File

@@ -109,6 +109,9 @@ var AST_Node = DEFNODE("Node", "start end", {
start: "[AST_Token] The first token of this node",
end: "[AST_Token] The last token of this node"
},
equals: function(node) {
return this.TYPE == node.TYPE && this._equals(node);
},
walk: function(visitor) {
visitor.visit(this);
},
@@ -125,12 +128,7 @@ var AST_Node = DEFNODE("Node", "start end", {
var marker = {};
this.walk(new TreeWalker(function(node) {
if (node.validate_visited === marker) {
throw new Error(string_template("cannot reuse {type} from [{file}:{line},{col}]", {
type: "AST_" + node.TYPE,
file: node.start.file,
line: node.start.line,
col: node.start.col,
}));
throw new Error(string_template("cannot reuse AST_{TYPE} from [{start}]", node));
}
node.validate_visited = marker;
}));
@@ -138,6 +136,7 @@ var AST_Node = DEFNODE("Node", "start end", {
}, null);
DEF_BITPROPS(AST_Node, [
// AST_Node
"_optimized",
"_squeezed",
// AST_Call
@@ -172,6 +171,8 @@ DEF_BITPROPS(AST_Node, [
"pure",
// AST_Assign
"redundant",
// AST_Node
"single_use",
// AST_ClassProperty
"static",
// AST_Call
@@ -231,6 +232,24 @@ AST_Node.disable_validation = function() {
while (restore = restore_transforms.pop()) restore();
};
function all_equals(k, l) {
return k.length == l.length && all(k, function(m, i) {
return m.equals(l[i]);
});
}
function list_equals(s, t) {
return s.length == t.length && all(s, function(u, i) {
return u == t[i];
});
}
function prop_equals(u, v) {
if (u === v) return true;
if (u == null) return v == null;
return u instanceof AST_Node && v instanceof AST_Node && u.equals(v);
}
/* -----[ statements ]----- */
var AST_Statement = DEFNODE("Statement", null, {
@@ -242,6 +261,7 @@ var AST_Statement = DEFNODE("Statement", null, {
var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
_equals: return_true,
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "quote value", {
@@ -250,6 +270,9 @@ var AST_Directive = DEFNODE("Directive", "quote value", {
quote: "[string?] the original quote character",
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
},
_equals: function(node) {
return this.value == node.value;
},
_validate: function() {
if (this.quote != null) {
if (typeof this.quote != "string") throw new Error("quote must be string");
@@ -260,7 +283,8 @@ var AST_Directive = DEFNODE("Directive", "quote value", {
}, AST_Statement);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)"
$documentation: "The empty statement (empty block or simply a semicolon)",
_equals: return_true,
}, AST_Statement);
function is_statement(node) {
@@ -291,6 +315,9 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
$propdoc: {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)",
},
_equals: function(node) {
return this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -305,7 +332,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any inner scopes",
functions: "[Dictionary/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Dictionary/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
@@ -342,6 +369,9 @@ var AST_Block = DEFNODE("Block", "body", {
$propdoc: {
body: "[AST_Statement*] an array of statements"
},
_equals: function(node) {
return all_equals(this.body, node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -376,6 +406,10 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
$propdoc: {
label: "[AST_Label] a label definition"
},
_equals: function(node) {
return this.label.equals(node.label)
&& this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -417,6 +451,10 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
$propdoc: {
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
},
_equals: function(node) {
return this.body.equals(node.body)
&& this.condition.equals(node.condition);
},
_validate: function() {
if (this.TYPE == "DWLoop") throw new Error("should not instantiate AST_DWLoop");
must_be_expression(this, "condition");
@@ -431,7 +469,7 @@ var AST_Do = DEFNODE("Do", null, {
node.body.walk(visitor);
node.condition.walk(visitor);
});
}
},
}, AST_DWLoop);
var AST_While = DEFNODE("While", null, {
@@ -442,7 +480,7 @@ var AST_While = DEFNODE("While", null, {
node.condition.walk(visitor);
node.body.walk(visitor);
});
}
},
}, AST_DWLoop);
var AST_For = DEFNODE("For", "init condition step", {
@@ -452,6 +490,12 @@ var AST_For = DEFNODE("For", "init condition step", {
condition: "[AST_Node?] the `for` termination clause, or null if empty",
step: "[AST_Node?] the `for` update clause, or null if empty"
},
_equals: function(node) {
return prop_equals(this.init, node.init)
&& prop_equals(this.condition, node.condition)
&& prop_equals(this.step, node.step)
&& this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -479,6 +523,11 @@ var AST_ForEnumeration = DEFNODE("ForEnumeration", "init object", {
init: "[AST_Node] the assignment target during iteration",
object: "[AST_Node] the object to iterate over"
},
_equals: function(node) {
return this.init.equals(node.init)
&& this.object.equals(node.object)
&& this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -519,6 +568,10 @@ var AST_With = DEFNODE("With", "expression", {
$propdoc: {
expression: "[AST_Node] the `with` expression"
},
_equals: function(node) {
return this.expression.equals(node.expression)
&& this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -534,7 +587,7 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "fn_defs may_call_this uses_eval uses_with", {
$documentation: "Base class for all statements introducing a lexical scope",
$documentation: "Base class for all statements introducing a lambda scope",
$propdoc: {
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
@@ -592,6 +645,10 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
}
}, AST_Scope);
var AST_ClassInitBlock = DEFNODE("ClassInitBlock", null, {
$documentation: "Value for `class` static initialization blocks",
}, AST_Scope);
var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest safe_ids uses_arguments", {
$documentation: "Base class for functions",
$propdoc: {
@@ -617,6 +674,13 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest safe_ids uses_argu
});
if (this.rest) this.rest.walk(tw);
},
_equals: function(node) {
return prop_equals(this.rest, node.rest)
&& prop_equals(this.name, node.name)
&& prop_equals(this.value, node.value)
&& all_equals(this.argnames, node.argnames)
&& all_equals(this.body, node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -827,6 +891,14 @@ var AST_Class = DEFNODE("Class", "extends name properties", {
extends: "[AST_Node?] the super class, or null if not specified",
properties: "[AST_ClassProperty*] array of class properties",
},
_equals: function(node) {
return prop_equals(this.name, node.name)
&& prop_equals(this.extends, node.extends)
&& all_equals(this.properties, node.properties);
},
resolve: function(def_class) {
return def_class ? this : this.parent_scope.resolve();
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -851,9 +923,6 @@ var AST_DefClass = DEFNODE("DefClass", null, {
$propdoc: {
name: "[AST_SymbolDefClass] the name of this class",
},
resolve: function(def_class) {
return def_class ? this : this.parent_scope.resolve();
},
_validate: function() {
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
},
@@ -874,11 +943,17 @@ var AST_ClassExpression = DEFNODE("ClassExpression", null, {
var AST_ClassProperty = DEFNODE("ClassProperty", "key private static value", {
$documentation: "Base class for `class` properties",
$propdoc: {
key: "[string|AST_Node] property name (AST_Node for computed property)",
key: "[string|AST_Node?] property name (AST_Node for computed property, null for initialization block)",
private: "[boolean] whether this is a private property",
static: "[boolean] whether this is a static property",
value: "[AST_Node?] property value (AST_Accessor for getters/setters, AST_LambdaExpression for methods, null if not specified for fields)",
},
_equals: function(node) {
return !this.private == !node.private
&& !this.static == !node.static
&& prop_equals(this.key, node.key)
&& prop_equals(this.value, node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -888,7 +963,9 @@ var AST_ClassProperty = DEFNODE("ClassProperty", "key private static value", {
},
_validate: function() {
if (this.TYPE == "ClassProperty") throw new Error("should not instantiate AST_ClassProperty");
if (typeof this.key != "string") {
if (this instanceof AST_ClassInit) {
if (this.key != null) throw new Error("key must be null");
} else if (typeof this.key != "string") {
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
must_be_expression(this, "key");
}
@@ -928,6 +1005,17 @@ var AST_ClassMethod = DEFNODE("ClassMethod", null, {
},
}, AST_ClassProperty);
var AST_ClassInit = DEFNODE("ClassInit", null, {
$documentation: "A `class` static initialization block",
_validate: function() {
if (!this.static) throw new Error("static must be true");
if (!(this.value instanceof AST_ClassInitBlock)) throw new Error("value must be AST_ClassInitBlock");
},
initialize: function() {
this.static = true;
},
}, AST_ClassProperty);
/* -----[ JUMPS ]----- */
var AST_Jump = DEFNODE("Jump", null, {
@@ -942,6 +1030,9 @@ var AST_Exit = DEFNODE("Exit", "value", {
$propdoc: {
value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
},
_equals: function(node) {
return prop_equals(this.value, node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -972,6 +1063,9 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
$propdoc: {
label: "[AST_LabelRef?] the label, or null if none",
},
_equals: function(node) {
return prop_equals(this.label, node.label);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1002,6 +1096,11 @@ var AST_If = DEFNODE("If", "condition alternative", {
condition: "[AST_Node] the `if` condition",
alternative: "[AST_Statement?] the `else` part, or null if not present"
},
_equals: function(node) {
return this.body.equals(node.body)
&& this.condition.equals(node.condition)
&& prop_equals(this.alternative, node.alternative);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1025,6 +1124,10 @@ var AST_Switch = DEFNODE("Switch", "expression", {
$propdoc: {
expression: "[AST_Node] the `switch` “discriminant”"
},
_equals: function(node) {
return this.expression.equals(node.expression)
&& all_equals(this.body, node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1056,6 +1159,10 @@ var AST_Case = DEFNODE("Case", "expression", {
$propdoc: {
expression: "[AST_Node] the `case` expression"
},
_equals: function(node) {
return this.expression.equals(node.expression)
&& all_equals(this.body, node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1076,6 +1183,11 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
bcatch: "[AST_Catch?] the catch block, or null if not present",
bfinally: "[AST_Finally?] the finally block, or null if not present"
},
_equals: function(node) {
return all_equals(this.body, node.body)
&& prop_equals(this.bcatch, node.bcatch)
&& prop_equals(this.bfinally, node.bfinally);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1099,6 +1211,10 @@ var AST_Catch = DEFNODE("Catch", "argname", {
$propdoc: {
argname: "[(AST_Destructured|AST_SymbolCatch)?] symbol for the exception, or null if not present",
},
_equals: function(node) {
return prop_equals(this.argname, node.argname)
&& all_equals(this.body, node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1124,6 +1240,9 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
$propdoc: {
definitions: "[AST_VarDef*] array of variable definitions"
},
_equals: function(node) {
return all_equals(this.definitions, node.definitions);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1180,6 +1299,10 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer",
},
_equals: function(node) {
return this.name.equals(node.name)
&& prop_equals(this.value, node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1199,6 +1322,9 @@ var AST_ExportDeclaration = DEFNODE("ExportDeclaration", "body", {
$propdoc: {
body: "[AST_DefClass|AST_Definitions|AST_LambdaDefinition] the statement to export",
},
_equals: function(node) {
return this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1219,6 +1345,9 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
$propdoc: {
body: "[AST_Node] the default export",
},
_equals: function(node) {
return this.body.equals(node.body);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1232,29 +1361,29 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
},
}, AST_Statement);
var AST_ExportForeign = DEFNODE("ExportForeign", "aliases keys path quote", {
var AST_ExportForeign = DEFNODE("ExportForeign", "aliases keys path", {
$documentation: "An `export ... from '...'` statement",
$propdoc: {
aliases: "[string*] array of aliases to export",
keys: "[string*] array of keys to import",
path: "[string] the path to import module",
quote: "[string?] the original quote character",
aliases: "[AST_String*] array of aliases to export",
keys: "[AST_String*] array of keys to import",
path: "[AST_String] the path to import module",
},
_equals: function(node) {
return this.path.equals(node.path)
&& all_equals(this.aliases, node.aliases)
&& all_equals(this.keys, node.keys);
},
_validate: function() {
if (this.aliases.length != this.keys.length) {
throw new Error("aliases:key length mismatch: " + this.aliases.length + " != " + this.keys.length);
}
this.aliases.forEach(function(name) {
if (typeof name != "string") throw new Error("aliases must contain string");
if (!(name instanceof AST_String)) throw new Error("aliases must contain AST_String");
});
this.keys.forEach(function(name) {
if (typeof name != "string") throw new Error("keys must contain string");
if (!(name instanceof AST_String)) throw new Error("keys must contain AST_String");
});
if (typeof this.path != "string") throw new Error("path must be string");
if (this.quote != null) {
if (typeof this.quote != "string") throw new Error("quote must be string");
if (!/^["']$/.test(this.quote)) throw new Error("invalid quote: " + this.quote);
}
if (!(this.path instanceof AST_String)) throw new Error("path must be AST_String");
},
}, AST_Statement);
@@ -1263,6 +1392,9 @@ var AST_ExportReferences = DEFNODE("ExportReferences", "properties", {
$propdoc: {
properties: "[AST_SymbolExport*] array of aliases to export",
},
_equals: function(node) {
return all_equals(this.properties, node.properties);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1278,14 +1410,20 @@ var AST_ExportReferences = DEFNODE("ExportReferences", "properties", {
},
}, AST_Statement);
var AST_Import = DEFNODE("Import", "all default path properties quote", {
var AST_Import = DEFNODE("Import", "all default path properties", {
$documentation: "An `import` statement",
$propdoc: {
all: "[AST_SymbolImport?] the imported namespace, or null if not specified",
default: "[AST_SymbolImport?] the alias for default `export`, or null if not specified",
path: "[string] the path to import module",
path: "[AST_String] the path to import module",
properties: "[(AST_SymbolImport*)?] array of aliases, or null if not specified",
quote: "[string?] the original quote character",
},
_equals: function(node) {
return this.path.equals(node.path)
&& prop_equals(this.all, node.all)
&& prop_equals(this.default, node.default)
&& !this.properties == !node.properties
&& (!this.properties || all_equals(this.properties, node.properties));
},
walk: function(visitor) {
var node = this;
@@ -1304,16 +1442,12 @@ var AST_Import = DEFNODE("Import", "all default path properties quote", {
}
if (this.default != null) {
if (!(this.default instanceof AST_SymbolImport)) throw new Error("default must be AST_SymbolImport");
if (this.default.key !== "") throw new Error("invalid default key: " + this.default.key);
if (this.default.key.value !== "") throw new Error("invalid default key: " + this.default.key.value);
}
if (typeof this.path != "string") throw new Error("path must be string");
if (!(this.path instanceof AST_String)) throw new Error("path must be AST_String");
if (this.properties != null) this.properties.forEach(function(node) {
if (!(node instanceof AST_SymbolImport)) throw new Error("properties must contain AST_SymbolImport");
});
if (this.quote != null) {
if (typeof this.quote != "string") throw new Error("quote must be string");
if (!/^["']$/.test(this.quote)) throw new Error("invalid quote: " + this.quote);
}
},
}, AST_Statement);
@@ -1323,6 +1457,10 @@ var AST_DefaultValue = DEFNODE("DefaultValue", "name value", {
name: "[AST_Destructured|AST_SymbolDeclaration] name of the variable",
value: "[AST_Node] value to assign if variable is `undefined`",
},
_equals: function(node) {
return this.name.equals(node.name)
&& this.value.equals(node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1350,6 +1488,11 @@ var AST_Call = DEFNODE("Call", "args expression optional pure terminal", {
pure: "[boolean/S] marker for side-effect-free call expression",
terminal: "[boolean] whether the chain has ended",
},
_equals: function(node) {
return !this.optional == !node.optional
&& this.expression.equals(node.expression)
&& all_equals(this.args, node.args);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1376,7 +1519,10 @@ var AST_New = DEFNODE("New", null, {
var AST_Sequence = DEFNODE("Sequence", "expressions", {
$documentation: "A sequence expression (comma-separated expressions)",
$propdoc: {
expressions: "[AST_Node*] array of expressions (at least two)"
expressions: "[AST_Node*] array of expressions (at least two)",
},
_equals: function(node) {
return all_equals(this.expressions, node.expressions);
},
walk: function(visitor) {
var node = this;
@@ -1405,6 +1551,11 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression optional property termina
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
terminal: "[boolean] whether the chain has ended",
},
_equals: function(node) {
return !this.optional == !node.optional
&& prop_equals(this.property, node.property)
&& this.expression.equals(node.expression);
},
get_property: function() {
var p = this.property;
if (p instanceof AST_Constant) return p.value;
@@ -1417,8 +1568,11 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression optional property termina
},
});
var AST_Dot = DEFNODE("Dot", null, {
var AST_Dot = DEFNODE("Dot", "quoted", {
$documentation: "A dotted property access expression",
$propdoc: {
quoted: "[boolean] whether property is transformed from a quoted string",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1449,6 +1603,9 @@ var AST_Spread = DEFNODE("Spread", "expression", {
$propdoc: {
expression: "[AST_Node] expression to be expanded",
},
_equals: function(node) {
return this.expression.equals(node.expression);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1464,7 +1621,11 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
$documentation: "Base class for unary expressions",
$propdoc: {
operator: "[string] the operator",
expression: "[AST_Node] expression that this unary operator applies to"
expression: "[AST_Node] expression that this unary operator applies to",
},
_equals: function(node) {
return this.operator == node.operator
&& this.expression.equals(node.expression);
},
walk: function(visitor) {
var node = this;
@@ -1494,6 +1655,11 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
operator: "[string] the operator",
right: "[AST_Node] right-hand side expression"
},
_equals: function(node) {
return this.operator == node.operator
&& this.left.equals(node.left)
&& this.right.equals(node.right);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1515,6 +1681,11 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
consequent: "[AST_Node]",
alternative: "[AST_Node]"
},
_equals: function(node) {
return this.condition.equals(node.condition)
&& this.consequent.equals(node.consequent)
&& this.alternative.equals(node.alternative);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1556,6 +1727,9 @@ var AST_Await = DEFNODE("Await", "expression", {
$propdoc: {
expression: "[AST_Node] expression with Promise to resolve on",
},
_equals: function(node) {
return this.expression.equals(node.expression);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1573,6 +1747,10 @@ var AST_Yield = DEFNODE("Yield", "expression nested", {
expression: "[AST_Node?] return value for iterator, or null if undefined",
nested: "[boolean] whether to iterate over expression as generator",
},
_equals: function(node) {
return !this.nested == !node.nested
&& prop_equals(this.expression, node.expression);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1595,6 +1773,9 @@ var AST_Array = DEFNODE("Array", "elements", {
$propdoc: {
elements: "[AST_Node*] array of elements"
},
_equals: function(node) {
return all_equals(this.elements, node.elements);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1637,6 +1818,10 @@ var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
$propdoc: {
elements: "[(AST_DefaultValue|AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef)*] array of elements",
},
_equals: function(node) {
return prop_equals(this.rest, node.rest)
&& all_equals(this.elements, node.elements);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1654,6 +1839,10 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
value: "[AST_DefaultValue|AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef] property value",
},
_equals: function(node) {
return prop_equals(this.key, node.key)
&& this.value.equals(node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1675,6 +1864,10 @@ var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
$propdoc: {
properties: "[AST_DestructuredKeyVal*] array of properties",
},
_equals: function(node) {
return prop_equals(this.rest, node.rest)
&& all_equals(this.properties, node.properties);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1696,6 +1889,9 @@ var AST_Object = DEFNODE("Object", "properties", {
$propdoc: {
properties: "[(AST_ObjectProperty|AST_Spread)*] array of properties"
},
_equals: function(node) {
return all_equals(this.properties, node.properties);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1719,6 +1915,10 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
},
_equals: function(node) {
return prop_equals(this.key, node.key)
&& this.value.equals(node.value);
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -1773,6 +1973,9 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
thedef: "[SymbolDef/S] the definition of this symbol"
},
_equals: function(node) {
return this.thedef ? this.thedef === node.thedef : this.name == node.name;
},
_validate: function() {
if (this.TYPE == "Symbol") throw new Error("should not instantiate AST_Symbol");
if (typeof this.name != "string") throw new Error("name must be string");
@@ -1790,10 +1993,14 @@ var AST_SymbolConst = DEFNODE("SymbolConst", null, {
var AST_SymbolImport = DEFNODE("SymbolImport", "key", {
$documentation: "Symbol defined by an `import` statement",
$propdoc: {
key: "[string] the original `export` name",
key: "[AST_String] the original `export` name",
},
_equals: function(node) {
return this.name == node.name
&& this.key.equals(node.key);
},
_validate: function() {
if (typeof this.key != "string") throw new Error("key must be string");
if (!(this.key instanceof AST_String)) throw new Error("key must be AST_String");
},
}, AST_SymbolConst);
@@ -1837,7 +2044,7 @@ var AST_Label = DEFNODE("Label", "references", {
initialize: function() {
this.references = [];
this.thedef = this;
}
},
}, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
@@ -1847,10 +2054,14 @@ var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
var AST_SymbolExport = DEFNODE("SymbolExport", "alias", {
$documentation: "Reference in an `export` statement",
$propdoc: {
alias: "[string] the `export` alias",
alias: "[AST_String] the `export` alias",
},
_equals: function(node) {
return this.name == node.name
&& this.alias.equals(node.alias);
},
_validate: function() {
if (typeof this.alias != "string") throw new Error("alias must be string");
if (!(this.alias instanceof AST_String)) throw new Error("alias must be AST_String");
},
}, AST_SymbolRef);
@@ -1860,6 +2071,7 @@ var AST_LabelRef = DEFNODE("LabelRef", null, {
var AST_ObjectIdentity = DEFNODE("ObjectIdentity", null, {
$documentation: "Base class for `super` & `this`",
_equals: return_true,
_validate: function() {
if (this.TYPE == "ObjectIdentity") throw new Error("should not instantiate AST_ObjectIdentity");
},
@@ -1894,7 +2106,12 @@ var AST_Template = DEFNODE("Template", "expressions strings tag", {
$propdoc: {
expressions: "[AST_Node*] the placeholder expressions",
strings: "[string*] the raw text segments",
tag: "[AST_Node] tag function, or null if absent",
tag: "[AST_Node?] tag function, or null if absent",
},
_equals: function(node) {
return prop_equals(this.tag, node.tag)
&& list_equals(this.strings, node.strings)
&& all_equals(this.expressions, node.expressions);
},
walk: function(visitor) {
var node = this;
@@ -1919,6 +2136,9 @@ var AST_Template = DEFNODE("Template", "expressions strings tag", {
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
_equals: function(node) {
return this.value === node.value;
},
_validate: function() {
if (this.TYPE == "Constant") throw new Error("should not instantiate AST_Constant");
},
@@ -1967,6 +2187,9 @@ var AST_RegExp = DEFNODE("RegExp", "value", {
$propdoc: {
value: "[RegExp] the actual regexp"
},
_equals: function(node) {
return "" + this.value == "" + node.value;
},
_validate: function() {
if (!(this.value instanceof RegExp)) throw new Error("value must be RegExp");
},
@@ -1974,6 +2197,7 @@ var AST_RegExp = DEFNODE("RegExp", "value", {
var AST_Atom = DEFNODE("Atom", null, {
$documentation: "Base class for atoms",
_equals: return_true,
_validate: function() {
if (this.TYPE == "Atom") throw new Error("should not instantiate AST_Atom");
},
@@ -2039,16 +2263,21 @@ TreeWalker.prototype = {
return this.stack[this.stack.length - 2 - (n || 0)];
},
push: function(node) {
if (node instanceof AST_Lambda) {
var value;
if (node instanceof AST_Class) {
this.directives = Object.create(this.directives);
value = "use strict";
} else if (node instanceof AST_Directive) {
value = node.value;
} else if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
}
if (value && !this.directives[value]) this.directives[value] = node;
this.stack.push(node);
},
pop: function() {
var node = this.stack.pop();
if (node instanceof AST_Lambda) {
if (node instanceof AST_Class || node instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives);
}
},

File diff suppressed because it is too large Load Diff

View File

@@ -76,18 +76,20 @@ function minify(files, options) {
annotations: undefined,
compress: {},
enclose: false,
expression: false,
ie: false,
ie8: false,
keep_fargs: false,
keep_fnames: false,
mangle: {},
module: false,
nameCache: null,
output: {},
parse: {},
rename: undefined,
sourceMap: false,
timings: false,
toplevel: false,
toplevel: !!(options && options["module"]),
v8: false,
validate: false,
warnings: false,
@@ -97,10 +99,12 @@ function minify(files, options) {
if (options.validate) AST_Node.enable_validation();
var timings = options.timings && { start: Date.now() };
if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]);
if (options.expression) set_shorthand("expression", options, [ "compress", "parse" ]);
if (options.ie8) options.ie = options.ie || options.ie8;
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_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
if (options.module) set_shorthand("module", options, [ "compress", "parse" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);
@@ -151,13 +155,11 @@ function minify(files, options) {
}, options.warnings == "verbose");
if (timings) timings.parse = Date.now();
var toplevel;
if (files instanceof AST_Toplevel) {
options.parse = options.parse || {};
if (files instanceof AST_Node) {
toplevel = files;
} else {
if (typeof files == "string") {
files = [ files ];
}
options.parse = options.parse || {};
if (typeof files == "string") files = [ files ];
options.parse.toplevel = null;
var source_map_content = options.sourceMap && options.sourceMap.content;
if (typeof source_map_content == "string" && source_map_content != "inline") {
@@ -169,17 +171,14 @@ function minify(files, options) {
options.parse.toplevel = toplevel = parse(files[name], options.parse);
if (source_map_content == "inline") {
var inlined_content = read_source_map(name, toplevel);
if (inlined_content) {
options.sourceMap.orig[name] = parse_source_map(inlined_content);
}
if (inlined_content) options.sourceMap.orig[name] = parse_source_map(inlined_content);
} else if (source_map_content) {
options.sourceMap.orig[name] = source_map_content;
}
}
}
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
if (options.parse.expression) toplevel = toplevel.wrap_expression();
if (quoted_props) reserve_quoted_keys(toplevel, quoted_props);
[ "enclose", "wrap" ].forEach(function(action) {
var option = options[action];
if (!option) return;
@@ -206,7 +205,9 @@ function minify(files, options) {
toplevel.mangle_names(options.mangle);
}
if (timings) timings.properties = Date.now();
if (quoted_props) reserve_quoted_keys(toplevel, quoted_props);
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
if (options.parse.expression) toplevel = toplevel.unwrap_expression();
if (timings) timings.output = Date.now();
var result = {};
var output = defaults(options.output, {

View File

@@ -192,6 +192,19 @@
value: from_moz(M.value),
});
},
StaticBlock: function(M) {
var start = my_start_token(M);
var end = my_end_token(M);
return new AST_ClassInit({
start: start,
end: end,
value: new AST_ClassInitBlock({
start: start,
end: end,
body: normalize_directives(M.body.map(from_moz)),
}),
});
},
ForOfStatement: function(M) {
return new (M.await ? AST_ForAwaitOf : AST_ForOf)({
start: my_start_token(M),
@@ -303,13 +316,22 @@
});
},
ExportAllDeclaration: function(M) {
var alias = M.exported ? read_name(M.exported) : "*";
var start = my_start_token(M);
var end = my_end_token(M);
return new AST_ExportForeign({
start: my_start_token(M),
end: my_end_token(M),
aliases: [ alias ],
keys: [ "*" ],
path: M.source.value,
start: start,
end: end,
aliases: [ M.exported ? from_moz_alias(M.exported) : new AST_String({
start: start,
value: "*",
end: end,
}) ],
keys: [ new AST_String({
start: start,
value: "*",
end: end,
}) ],
path: from_moz(M.source),
});
},
ExportDefaultDeclaration: function(M) {
@@ -346,15 +368,15 @@
if (M.source) {
var aliases = [], keys = [];
M.specifiers.forEach(function(prop) {
aliases.push(read_name(prop.exported));
keys.push(read_name(prop.local));
aliases.push(from_moz_alias(prop.exported));
keys.push(from_moz_alias(prop.local));
});
return new AST_ExportForeign({
start: my_start_token(M),
end: my_end_token(M),
aliases: aliases,
keys: keys,
path: M.source.value,
path: from_moz(M.source),
});
}
return new AST_ExportReferences({
@@ -362,38 +384,48 @@
end: my_end_token(M),
properties: M.specifiers.map(function(prop) {
var sym = new AST_SymbolExport(from_moz(prop.local));
sym.alias = read_name(prop.exported);
sym.alias = from_moz_alias(prop.exported);
return sym;
}),
});
},
ImportDeclaration: function(M) {
var start = my_start_token(M);
var end = my_end_token(M);
var all = null, def = null, props = null;
M.specifiers.forEach(function(prop) {
var sym = new AST_SymbolImport(from_moz(prop.local));
switch (prop.type) {
case "ImportDefaultSpecifier":
def = sym;
def.key = "";
def.key = new AST_String({
start: start,
value: "",
end: end,
});
break;
case "ImportNamespaceSpecifier":
all = sym;
all.key = "*";
all.key = new AST_String({
start: start,
value: "*",
end: end,
});
break;
default:
sym.key = prop.imported.name || syn.name;
sym.key = from_moz_alias(prop.imported);
if (!props) props = [];
props.push(sym);
break;
}
});
return new AST_Import({
start: my_start_token(M),
end: my_end_token(M),
start: start,
end: end,
all: all,
default: def,
properties: props,
path: M.source.value,
path: from_moz(M.source),
});
},
ImportExpression: function(M) {
@@ -714,6 +746,10 @@
};
});
def_to_moz(AST_ClassInit, function To_Moz_StaticBlock(M) {
return to_moz_scope("StaticBlock", M.value);
});
function To_Moz_ForOfStatement(is_await) {
return function(M) {
return {
@@ -780,38 +816,26 @@
});
def_to_moz(AST_ExportForeign, function To_Moz_ExportAllDeclaration_ExportNamedDeclaration(M) {
if (M.keys[0] == "*") return {
if (M.keys[0].value == "*") return {
type: "ExportAllDeclaration",
exported: M.aliases[0] == "*" ? null : {
type: "Identifier",
name: M.aliases[0],
},
source: {
type: "Literal",
value: M.path,
},
exported: M.aliases[0].value == "*" ? null : to_moz_alias(M.aliases[0]),
source: to_moz(M.path),
};
var specifiers = [];
for (var i = 0; i < M.aliases.length; i++) {
specifiers.push({
specifiers.push(set_moz_loc({
start: M.keys[i].start,
end: M.aliases[i].end,
}, {
type: "ExportSpecifier",
exported: {
type: "Identifier",
name: M.aliases[i],
},
local: {
type: "Identifier",
name: M.keys[i],
},
});
local: to_moz_alias(M.keys[i]),
exported: to_moz_alias(M.aliases[i]),
}));
}
return {
type: "ExportNamedDeclaration",
specifiers: specifiers,
source: {
type: "Literal",
value: M.path,
},
source: to_moz(M.path),
};
});
@@ -819,44 +843,41 @@
return {
type: "ExportNamedDeclaration",
specifiers: M.properties.map(function(prop) {
return {
return set_moz_loc({
start: prop.start,
end: prop.alias.end,
}, {
type: "ExportSpecifier",
local: to_moz(prop),
exported: {
type: "Identifier",
name: prop.alias,
},
};
exported: to_moz_alias(prop.alias),
});
}),
};
});
def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) {
var specifiers = M.properties ? M.properties.map(function(prop) {
return {
return set_moz_loc({
start: prop.key.start,
end: prop.end,
}, {
type: "ImportSpecifier",
local: to_moz(prop),
imported: {
type: "Identifier",
name: prop.key,
},
};
imported: to_moz_alias(prop.key),
});
}) : [];
if (M.all) specifiers.unshift({
if (M.all) specifiers.unshift(set_moz_loc(M.all, {
type: "ImportNamespaceSpecifier",
local: to_moz(M.all),
});
if (M.default) specifiers.unshift({
}));
if (M.default) specifiers.unshift(set_moz_loc(M.default, {
type: "ImportDefaultSpecifier",
local: to_moz(M.default),
});
}));
return {
type: "ImportDeclaration",
specifiers: specifiers,
source: {
type: "Literal",
value: M.path,
},
source: to_moz(M.path),
};
});
@@ -1203,6 +1224,14 @@
return node;
}
function from_moz_alias(moz) {
return new AST_String({
start: my_start_token(moz),
value: read_name(moz),
end: my_end_token(moz),
});
}
AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK;
FROM_MOZ_STACK = [];
@@ -1254,6 +1283,13 @@
return node != null ? node.to_mozilla_ast() : null;
}
function to_moz_alias(alias) {
return is_identifier_string(alias.value) ? set_moz_loc(alias, {
type: "Identifier",
name: alias.value,
}) : to_moz(alias);
}
function to_moz_block(node) {
return {
type: "BlockStatement",

View File

@@ -55,6 +55,7 @@ function OutputStream(options) {
beautify : false,
braces : false,
comments : false,
extendscript : false,
galio : false,
ie : false,
indent_level : 4,
@@ -75,7 +76,7 @@ function OutputStream(options) {
wrap_iife : false,
}, true);
// Convert comment option to RegExp if neccessary and set up comments filter
// Convert comment option to RegExp if necessary and set up comments filter
var comment_filter = return_false; // Default case, throw all comments away
if (options.comments) {
var comments = options.comments;
@@ -260,6 +261,15 @@ function OutputStream(options) {
var require_semicolon = makePredicate("( [ + * / - , .");
function require_space(prev, ch, str) {
return is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last)
|| last == "--" && ch == ">"
|| last == "!" && str == "--"
|| prev == "/" && (str == "in" || str == "instanceof");
}
var print = options.beautify
|| options.comments
|| options.max_line_len
@@ -312,12 +322,7 @@ function OutputStream(options) {
}
if (might_need_space) {
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last)
|| str == "--" && last == "!"
|| str == "in" && prev == "/"
|| last == "--" && ch == ">") {
if (require_space(prev, ch, str)) {
output += " ";
current_col++;
}
@@ -355,14 +360,7 @@ function OutputStream(options) {
}
}
if (might_need_space) {
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last)
|| str == "--" && last == "!"
|| str == "in" && prev == "/"
|| last == "--" && ch == ">") {
output += " ";
}
if (require_space(prev, ch, str)) output += " ";
if (prev != "<" || str != "!") might_need_space = false;
}
output += str;
@@ -409,10 +407,11 @@ function OutputStream(options) {
print(";");
}
function with_block(cont) {
function with_block(cont, end) {
print("{");
newline();
with_indent(cont);
add_mapping(end);
indent();
print("}");
}
@@ -702,6 +701,7 @@ function OutputStream(options) {
if (p instanceof AST_Class) return true;
// (x++)[y]
// (typeof x).y
// https://github.com/mishoo/UglifyJS/issues/115
if (p instanceof AST_PropAccess) return p.expression === this;
// (~x)`foo`
if (p instanceof AST_Template) return p.tag === this;
@@ -877,7 +877,9 @@ function OutputStream(options) {
return needs_parens_assign_cond(this, output);
});
PARENS(AST_Conditional, function(output) {
return needs_parens_assign_cond(this, output);
return needs_parens_assign_cond(this, output)
// https://github.com/mishoo/UglifyJS/issues/1144
|| output.option("extendscript") && output.parent() instanceof AST_Conditional;
});
PARENS(AST_Yield, function(output) {
return needs_parens_assign_cond(this, output);
@@ -956,7 +958,7 @@ function OutputStream(options) {
if (self.body.length > 0) {
output.with_block(function() {
display_body(self.body, false, output, allow_directives);
});
}, self.end);
} else print_braced_empty(self, output);
}
DEFPRINT(AST_BlockStatement, function(output) {
@@ -995,7 +997,7 @@ function OutputStream(options) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
} else {
parenthesize_for_noin(self.init, output, true);
parenthesize_for_no_in(self.init, output, true);
}
output.print(";");
output.space();
@@ -1064,6 +1066,14 @@ function OutputStream(options) {
}
output.semicolon();
});
function print_alias(alias, output) {
var value = alias.value;
if (value == "*" || is_identifier_string(value)) {
output.print_name(value);
} else {
output.print_string(value, alias.quote);
}
}
DEFPRINT(AST_ExportForeign, function(output) {
var self = this;
output.print("export");
@@ -1071,7 +1081,7 @@ function OutputStream(options) {
var len = self.keys.length;
if (len == 0) {
print_braced_empty(self, output);
} else if (self.keys[0] == "*") {
} else if (self.keys[0].value == "*") {
print_entry(0);
} else output.with_block(function() {
output.indent();
@@ -1083,22 +1093,22 @@ function OutputStream(options) {
print_entry(i);
}
output.newline();
});
}, self.end);
output.space();
output.print("from");
output.space();
output.print_string(self.path, self.quote);
self.path.print(output);
output.semicolon();
function print_entry(index) {
var alias = self.aliases[index];
var key = self.keys[index];
output.print_name(key);
if (alias != key) {
print_alias(key, output);
if (alias.value != key.value) {
output.space();
output.print("as");
output.space();
output.print_name(alias);
print_alias(alias, output);
}
}
});
@@ -1127,7 +1137,7 @@ function OutputStream(options) {
output.print("from");
output.space();
}
output.print_string(self.path, self.quote);
self.path.print(output);
output.semicolon();
});
@@ -1257,6 +1267,11 @@ function OutputStream(options) {
}
print_method(self, output);
});
DEFPRINT(AST_ClassInit, function(output) {
output.print("static");
output.space();
print_braced(this.value, output);
});
/* -----[ jumps ]----- */
function print_jump(kind, prop) {
@@ -1342,7 +1357,7 @@ function OutputStream(options) {
if (i < last && branch.body.length > 0)
output.newline();
});
});
}, self.end);
});
function print_branch_body(self, output) {
output.newline();
@@ -1398,7 +1413,7 @@ function OutputStream(options) {
print_braced(this, output);
});
function print_definitinos(type) {
function print_definitions(type) {
return function(output) {
var self = this;
output.print(type);
@@ -1411,15 +1426,15 @@ function OutputStream(options) {
if (!(p instanceof AST_IterationStatement && p.init === self)) output.semicolon();
};
}
DEFPRINT(AST_Const, print_definitinos("const"));
DEFPRINT(AST_Let, print_definitinos("let"));
DEFPRINT(AST_Var, print_definitinos("var"));
DEFPRINT(AST_Const, print_definitions("const"));
DEFPRINT(AST_Let, print_definitions("let"));
DEFPRINT(AST_Var, print_definitions("var"));
function parenthesize_for_noin(node, output, noin) {
function parenthesize_for_no_in(node, output, no_in) {
var parens = false;
// need to take some precautions here:
// https://github.com/mishoo/UglifyJS/issues/60
if (noin) node.walk(new TreeWalker(function(node) {
if (no_in) node.walk(new TreeWalker(function(node) {
if (parens) return true;
if (node instanceof AST_Binary && node.operator == "in") return parens = true;
if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true;
@@ -1435,8 +1450,8 @@ function OutputStream(options) {
output.print("=");
output.space();
var p = output.parent(1);
var noin = p instanceof AST_For || p instanceof AST_ForEnumeration;
parenthesize_for_noin(self.value, output, noin);
var no_in = p instanceof AST_For || p instanceof AST_ForEnumeration;
parenthesize_for_no_in(self.value, output, no_in);
}
});
@@ -1462,14 +1477,12 @@ function OutputStream(options) {
output.print("/*@__PURE__*/");
}
function print_call_args(self, output) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function() {
self.args.forEach(function(expr, i) {
if (i) output.comma();
expr.print(output);
});
output.add_mapping(self.end);
});
}
DEFPRINT(AST_Call, function(output) {
@@ -1504,11 +1517,12 @@ function OutputStream(options) {
var expr = self.expression;
expr.print(output);
var prop = self.property;
if (output.option("ie") && RESERVED_WORDS[prop]) {
output.print(self.optional ? "?.[" : "[");
if (output.option("ie") && RESERVED_WORDS[prop] || self.quoted && output.option("keep_quoted_props")) {
if (self.optional) output.print("?.");
output.with_square(function() {
output.add_mapping(self.end);
output.print_string(prop);
output.print("]");
});
} else {
if (expr instanceof AST_Number && !/[ex.)]/i.test(output.last())) output.print(".");
output.print(self.optional ? "?." : ".");
@@ -1520,9 +1534,10 @@ function OutputStream(options) {
DEFPRINT(AST_Sub, function(output) {
var self = this;
self.expression.print(output);
output.print(self.optional ? "?.[" : "[");
if (self.optional) output.print("?.");
output.with_square(function() {
self.property.print(output);
output.print("]");
});
});
DEFPRINT(AST_Spread, function(output) {
output.print("...");
@@ -1541,8 +1556,10 @@ function OutputStream(options) {
exp.print(output);
});
DEFPRINT(AST_UnaryPostfix, function(output) {
this.expression.print(output);
output.print(this.operator);
var self = this;
self.expression.print(output);
output.add_mapping(self.end);
output.print(self.operator);
});
DEFPRINT(AST_Binary, function(output) {
var self = this;
@@ -1635,7 +1652,8 @@ function OutputStream(options) {
value.print(output);
});
DEFPRINT(AST_DestructuredObject, function(output) {
var props = this.properties, len = props.length, rest = this.rest;
var self = this;
var props = self.properties, len = props.length, rest = self.rest;
if (len || rest) output.with_block(function() {
props.forEach(function(prop, i) {
if (i) {
@@ -1655,8 +1673,8 @@ function OutputStream(options) {
rest.print(output);
}
output.newline();
});
else print_braced_empty(this, output);
}, self.end);
else print_braced_empty(self, output);
});
function print_properties(self, output, no_comma) {
var props = self.properties;
@@ -1670,7 +1688,7 @@ function OutputStream(options) {
prop.print(output);
});
output.newline();
});
}, self.end);
else print_braced_empty(self, output);
}
DEFPRINT(AST_Object, function(output) {
@@ -1732,19 +1750,19 @@ function OutputStream(options) {
var name = get_symbol_name(self);
output.print_name(name);
var alias = self.alias;
if (alias != name) {
if (alias.value != name) {
output.space();
output.print("as");
output.space();
output.print_name(alias);
print_alias(alias, output);
}
});
DEFPRINT(AST_SymbolImport, function(output) {
var self = this;
var name = get_symbol_name(self);
var key = self.key;
if (key && key != name) {
output.print_name(key);
if (key.value && key.value != name) {
print_alias(key, output);
output.space();
output.print("as");
output.space();
@@ -1814,9 +1832,6 @@ function OutputStream(options) {
case "\u2029": return "\\u2029";
}
}));
var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === this)
output.print(" ");
});
function force_statement(stat, output) {
@@ -1883,7 +1898,7 @@ function OutputStream(options) {
output.indent();
stmt.print(output);
output.newline();
});
}, stmt.end);
}
/* -----[ source map generators ]----- */
@@ -1906,22 +1921,27 @@ function OutputStream(options) {
// or if we should add even more.
DEFMAP([
AST_Array,
AST_Await,
AST_BlockStatement,
AST_Catch,
AST_Constant,
AST_Debugger,
AST_Definitions,
AST_Destructured,
AST_Directive,
AST_Finally,
AST_Jump,
AST_Lambda,
AST_New,
AST_Object,
AST_Spread,
AST_StatementWithBody,
AST_Symbol,
AST_Switch,
AST_SwitchBranch,
AST_Try,
AST_UnaryPrefix,
AST_Yield,
], function(output) {
output.add_mapping(this.start);
});

View File

@@ -237,8 +237,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
newline_before : false,
regex_allowed : false,
comments_before : [],
directives : {},
directive_stack : [],
directives : Object.create(null),
read_template : with_eof_error("Unterminated template literal", function(strings) {
var s = "";
for (;;) {
@@ -553,16 +552,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function handle_dot() {
next();
var ch = peek();
if (ch == ".") {
var op = ".";
do {
op += ".";
next();
} while (peek() == ".");
return token("operator", op);
}
return is_digit(ch.charCodeAt(0)) ? read_num(".") : token("punc", ".");
if (looking_at("..")) return token("operator", "." + next() + next());
return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
}
function read_word() {
@@ -635,24 +626,19 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
};
next_token.add_directive = function(directive) {
S.directive_stack[S.directive_stack.length - 1].push(directive);
if (S.directives[directive]) S.directives[directive]++;
else S.directives[directive] = 1;
S.directives[directive] = true;
}
next_token.push_directives_stack = function() {
S.directive_stack.push([]);
S.directives = Object.create(S.directives);
}
next_token.pop_directives_stack = function() {
var directives = S.directive_stack.pop();
for (var i = directives.length; --i >= 0;) {
S.directives[directives[i]]--;
}
S.directives = Object.getPrototypeOf(S.directives);
}
next_token.has_directive = function(directive) {
return S.directives[directive] > 0;
return !!S.directives[directive];
}
return next_token;
@@ -699,6 +685,7 @@ function parse($TEXT, options) {
expression : false,
filename : null,
html5_comments : true,
module : false,
shebang : true,
strict : false,
toplevel : null,
@@ -795,7 +782,7 @@ function parse($TEXT, options) {
else if (!optional && !can_insert_semicolon()) expect(";");
}
function parenthesised() {
function parenthesized() {
expect("(");
var exp = expression();
expect(")");
@@ -820,7 +807,7 @@ function parse($TEXT, options) {
}
}
var statement = embed_tokens(function() {
var statement = embed_tokens(function(toplevel) {
handle_regexp();
switch (S.token.type) {
case "string":
@@ -859,15 +846,15 @@ function parse($TEXT, options) {
if (S.in_async) return simple_statement();
break;
case "export":
if (!toplevel && options.module !== "") unexpected();
next();
return export_();
case "import":
var token = peek();
if (!(token.type == "punc" && /^[(.]$/.test(token.value))) {
if (token.type == "punc" && /^[(.]$/.test(token.value)) break;
if (!toplevel && options.module !== "") unexpected();
next();
return import_();
}
break;
case "let":
if (is_vardefs()) {
next();
@@ -933,18 +920,18 @@ function parse($TEXT, options) {
next();
var body = in_loop(statement);
expect_token("keyword", "while");
var condition = parenthesised();
var condition = parenthesized();
semicolon(true);
return new AST_Do({
body : body,
condition : condition
condition : condition,
});
case "while":
next();
return new AST_While({
condition : parenthesised(),
body : in_loop(statement)
condition : parenthesized(),
body : in_loop(statement),
});
case "for":
@@ -972,15 +959,13 @@ function parse($TEXT, options) {
value = expression();
semicolon();
}
return new AST_Return({
value: value
});
return new AST_Return({ value: value });
case "switch":
next();
return new AST_Switch({
expression : parenthesised(),
body : in_loop(switch_body_)
expression : parenthesized(),
body : in_loop(switch_body_),
});
case "throw":
@@ -989,9 +974,7 @@ function parse($TEXT, options) {
croak("Illegal newline after 'throw'");
var value = expression();
semicolon();
return new AST_Throw({
value: value
});
return new AST_Throw({ value: value });
case "try":
next();
@@ -1009,8 +992,8 @@ function parse($TEXT, options) {
}
next();
return new AST_With({
expression : parenthesised(),
body : statement()
expression : parenthesized(),
body : statement(),
});
}
}
@@ -1069,13 +1052,13 @@ function parse($TEXT, options) {
return stat;
}
function has_modifier(name) {
function has_modifier(name, no_nlb) {
if (!is("name", name)) return;
var token = peek();
if (!token) return;
if (is_token(token, "operator", "=")) return;
if (token.type == "punc" && /^[(;}]$/.test(token.value)) return;
if (has_newline_before(token)) return;
if (no_nlb && has_newline_before(token)) return;
return next();
}
@@ -1105,7 +1088,7 @@ function parse($TEXT, options) {
}
var start = S.token;
var fixed = !!has_modifier("static");
var async = has_modifier("async");
var async = has_modifier("async", true);
if (is("operator", "*")) {
next();
var internal = is("name") && /^#/.test(S.token.value);
@@ -1124,6 +1107,18 @@ function parse($TEXT, options) {
}));
continue;
}
if (fixed && is("punc", "{")) {
props.push(new AST_ClassInit({
start: start,
value: new AST_ClassInitBlock({
start: start,
body: block_(),
end: prev(),
}),
end: prev(),
}));
continue;
}
var internal = is("name") && /^#/.test(S.token.value);
var key = as_property_key();
if (is("punc", "(")) {
@@ -1340,11 +1335,11 @@ function parse($TEXT, options) {
var loop = S.in_loop;
var labels = S.labels;
++S.in_function;
S.in_directives = true;
S.input.push_directives_stack();
S.in_loop = 0;
S.labels = [];
if (is("punc", "{")) {
S.in_directives = true;
body = block_();
value = null;
} else {
@@ -1412,7 +1407,7 @@ function parse($TEXT, options) {
name: name,
argnames: argnames,
rest: argnames.rest || null,
body: body
body: body,
});
if (is_strict) {
if (name) strict_verify_symbol(name);
@@ -1422,41 +1417,54 @@ function parse($TEXT, options) {
};
function if_() {
var cond = parenthesised(), body = statement(), belse = null;
var cond = parenthesized(), body = statement(), alt = null;
if (is("keyword", "else")) {
next();
belse = statement();
alt = statement();
}
return new AST_If({
condition : cond,
body : body,
alternative : belse
alternative : alt,
});
}
function is_alias() {
return is("name") || is_identifier_string(S.token.value);
return is("name") || is("string") || is_identifier_string(S.token.value);
}
function make_string(token) {
return new AST_String({
start: token,
quote: token.quote,
value: token.value,
end: token,
});
}
function as_path() {
var path = S.token;
expect_token("string");
semicolon();
return make_string(path);
}
function export_() {
if (is("operator", "*")) {
var key = S.token;
var alias = key;
next();
var alias = "*";
if (is("name", "as")) {
next();
if (!is_alias()) expect_token("name");
alias = S.token.value;
alias = S.token;
next();
}
expect_token("name", "from");
var path = S.token;
expect_token("string");
semicolon();
return new AST_ExportForeign({
aliases: [ alias ],
keys: [ "*" ],
path: path.value,
quote: path.quote,
aliases: [ make_string(alias) ],
keys: [ make_string(key) ],
path: as_path(),
});
}
if (is("punc", "{")) {
@@ -1470,26 +1478,20 @@ function parse($TEXT, options) {
if (is("name", "as")) {
next();
if (!is_alias()) expect_token("name");
aliases.push(S.token.value);
aliases.push(S.token);
next();
} else {
aliases.push(key.value);
aliases.push(key);
}
if (!is("punc", "}")) expect(",");
}
expect("}");
if (is("name", "from")) {
next();
var path = S.token;
expect_token("string");
semicolon();
return new AST_ExportForeign({
aliases: aliases,
keys: keys.map(function(token) {
return token.value;
}),
path: path.value,
quote: path.quote,
aliases: aliases.map(make_string),
keys: keys.map(make_string),
path: as_path(),
});
}
semicolon();
@@ -1497,7 +1499,7 @@ function parse($TEXT, options) {
properties: keys.map(function(token, index) {
if (!is_token(token, "name")) token_error(token, "Name expected");
var sym = _make_symbol(AST_SymbolExport, token);
sym.alias = aliases[index];
sym.alias = make_string(aliases[index]);
return sym;
}),
});
@@ -1587,26 +1589,42 @@ function parse($TEXT, options) {
var all = null;
var def = as_symbol(AST_SymbolImport, true);
var props = null;
if (def ? (def.key = "", is("punc", ",") && next()) : !is("string")) {
var cont;
if (def) {
def.key = new AST_String({
start: def.start,
value: "",
end: def.end,
});
if (cont = is("punc", ",")) next();
} else {
cont = !is("string");
}
if (cont) {
if (is("operator", "*")) {
var key = S.token;
next();
expect_token("name", "as");
all = as_symbol(AST_SymbolImport);
all.key = "*";
all.key = make_string(key);
} else {
expect("{");
props = [];
while (is_alias()) {
var alias;
if (is_token(peek(), "name", "as")) {
var key = S.token.value;
var key = S.token;
next();
next();
alias = as_symbol(AST_SymbolImport);
alias.key = key;
alias.key = make_string(key);
} else {
alias = as_symbol(AST_SymbolImport);
alias.key = alias.name;
alias.key = new AST_String({
start: alias.start,
value: alias.name,
end: alias.end,
});
}
props.push(alias);
if (!is("punc", "}")) expect(",");
@@ -1615,15 +1633,11 @@ function parse($TEXT, options) {
}
}
if (all || def || props) expect_token("name", "from");
var path = S.token;
expect_token("string");
semicolon();
return new AST_Import({
all: all,
default: def,
path: path.value,
path: as_path(),
properties: props,
quote: path.quote,
});
}
@@ -1801,7 +1815,7 @@ function parse($TEXT, options) {
ret = new AST_BigInt({ value: value });
break;
case "string":
ret = new AST_String({ value : value, quote : tok.quote });
ret = new AST_String({ value: value, quote: tok.quote });
break;
case "regexp":
ret = new AST_RegExp({ value: value });
@@ -2153,9 +2167,9 @@ function parse($TEXT, options) {
token_error(sym.start, "Unexpected " + sym.name + " in strict mode");
}
function as_symbol(type, noerror) {
function as_symbol(type, no_error) {
if (!is("name")) {
if (!noerror) croak("Name expected");
if (!no_error) croak("Name expected");
return null;
}
var sym = _make_symbol(type, S.token);
@@ -2391,20 +2405,20 @@ function parse($TEXT, options) {
return new ctor({ operator: op, expression: expr });
}
var expr_op = function(left, min_prec, no_in) {
var expr_op = function(left, min_precision, no_in) {
var op = is("operator") ? S.token.value : null;
if (op == "in" && no_in) op = null;
var prec = op != null ? PRECEDENCE[op] : null;
if (prec != null && prec > min_prec) {
var precision = op != null ? PRECEDENCE[op] : null;
if (precision != null && precision > min_precision) {
next();
var right = expr_op(maybe_unary(no_in), op == "**" ? prec - 1 : prec, no_in);
var right = expr_op(maybe_unary(no_in), op == "**" ? precision - 1 : precision, no_in);
return expr_op(new AST_Binary({
start : left.start,
left : left,
operator : op,
right : right,
end : right.end
}), min_prec, no_in);
end : right.end,
}), min_precision, no_in);
}
return left;
};
@@ -2550,9 +2564,13 @@ function parse($TEXT, options) {
return function() {
var start = S.token;
var body = [];
if (options.module) {
S.in_async = true;
S.input.add_directive("use strict");
}
S.input.push_directives_stack();
while (!is("eof"))
body.push(statement());
body.push(statement(true));
S.input.pop_directives_stack();
var end = prev() || start;
var toplevel = options.toplevel;

View File

@@ -43,10 +43,11 @@
"use strict";
var builtins = function() {
function get_builtins() {
var names = new Dictionary();
// NaN will be included due to Number.NaN
// constants
[
"NaN",
"null",
"true",
"false",
@@ -54,37 +55,85 @@ var builtins = function() {
"-Infinity",
"undefined",
].forEach(add);
// global functions
[
Array,
Boolean,
Date,
Error,
Function,
Math,
Number,
Object,
RegExp,
String,
].forEach(function(ctor) {
"encodeURI",
"encodeURIComponent",
"escape",
"eval",
"decodeURI",
"decodeURIComponent",
"isFinite",
"isNaN",
"parseFloat",
"parseInt",
"unescape",
].forEach(add);
// global constructors & objects
var global = Function("return this")();
[
"Array",
"ArrayBuffer",
"Atomics",
"BigInt",
"Boolean",
"console",
"DataView",
"Date",
"Error",
"Function",
"Int8Array",
"Intl",
"JSON",
"Map",
"Math",
"Number",
"Object",
"Promise",
"Proxy",
"Reflect",
"RegExp",
"Set",
"String",
"Symbol",
"WebAssembly",
].forEach(function(name) {
add(name);
var ctor = global[name];
if (!ctor) return;
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
if (typeof ctor != "function") return;
if (ctor.__proto__) Object.getOwnPropertyNames(ctor.__proto__).map(add);
if (ctor.prototype) Object.getOwnPropertyNames(ctor.prototype).map(add);
try {
Object.getOwnPropertyNames(new ctor()).map(add);
Object.getOwnPropertyNames(ctor.prototype).map(add);
} catch (e) {
try {
Object.getOwnPropertyNames(ctor()).map(add);
} catch (e) {}
}
});
return names;
return (get_builtins = function() {
return names.clone();
})();
function add(name) {
names.set(name, true);
}
}();
}
function reserve_quoted_keys(ast, reserved) {
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ClassProperty) {
if (node.start && node.start.quote) add(node.key);
} else if (node instanceof AST_ObjectProperty) {
if (node.start && node.start.quote) add(node.key);
if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else if (node.start && node.start.quote) {
add(node.key);
}
} else if (node instanceof AST_Dot) {
if (node.quoted) add(node.property);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
@@ -111,12 +160,16 @@ function mangle_properties(ast, options) {
builtins: false,
cache: null,
debug: false,
domprops: false,
keep_quoted: false,
regex: null,
reserved: null,
}, true);
var reserved = options.builtins ? new Dictionary() : builtins.clone();
var reserved = options.builtins ? new Dictionary() : get_builtins();
if (!options.domprops && typeof domprops !== "undefined") domprops.forEach(function(name) {
reserved.set(name, true);
});
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
reserved.set(name, true);
});
@@ -135,7 +188,7 @@ function mangle_properties(ast, options) {
var regex = options.regex;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
// note debug may be enabled as an empty string, which is falsy. Also treat passing 'true'
// the same as passing an empty string.
var debug = options.debug !== false;
var debug_suffix;
@@ -146,9 +199,7 @@ function mangle_properties(ast, options) {
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_Binary) {
if (node.operator == "in") addStrings(node.left, add);
} else if (node.TYPE == "Call") {
if (node.TYPE == "Call") {
var exp = node.expression;
if (exp instanceof AST_Dot) switch (exp.property) {
case "defineProperty":
@@ -165,14 +216,18 @@ function mangle_properties(ast, options) {
addStrings(node.args[0], add);
break;
}
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") add(node.key);
} else if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
addStrings(node.key, add);
} else {
add(node.key);
}
} else if (node instanceof AST_Dot) {
add(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") add(node.key);
if (is_lhs(node, this.parent())) add(node.property);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
if (is_lhs(node, this.parent())) addStrings(node.property, add);
}
}));
@@ -197,12 +252,16 @@ function mangle_properties(ast, options) {
mangleStrings(node.args[0]);
break;
}
} else if (node instanceof AST_ClassProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_ClassProperty
|| node instanceof AST_DestructuredKeyVal
|| node instanceof AST_ObjectProperty) {
if (node.key instanceof AST_Node) {
mangleStrings(node.key);
} else {
node.key = mangle(node.key);
}
} else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_Sub) {
if (!options.keep_quoted) mangleStrings(node.property);
}
@@ -217,8 +276,14 @@ function mangle_properties(ast, options) {
}
function should_mangle(name) {
if (reserved.has(name)) return false;
if (regex && !regex.test(name)) return false;
if (reserved.has(name)) {
AST_Node.info("Preserving reserved property {this}", name);
return false;
}
if (regex && !regex.test(name)) {
AST_Node.info("Preserving excluded property {this}", name);
return false;
}
return cache.has(name) || names_to_mangle.has(name);
}
@@ -243,12 +308,16 @@ function mangle_properties(ast, options) {
if (/^#/.test(name)) mangled = "#" + mangled;
cache.set(name, mangled);
}
AST_Node.info("Mapping property {name} to {mangled}", {
mangled: mangled,
name: name,
});
return mangled;
}
function mangleStrings(node) {
if (node instanceof AST_Sequence) {
mangleStrings(node.expressions.tail_node());
mangleStrings(node.tail_node());
} else if (node instanceof AST_String) {
node.value = mangle(node.value);
} else if (node instanceof AST_Conditional) {

View File

@@ -64,19 +64,20 @@ SymbolDef.prototype = {
this.references.forEach(fn);
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
if (this.global && cache && cache.has(this.name)) {
if (this.mangled_name) return;
var cache = this.global && options.cache && options.cache.props;
if (cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name);
} else if (!this.mangled_name && !this.unmangleable(options)) {
} else if (this.unmangleable(options)) {
names_in_use(this.scope, options).set(this.name, true);
} else {
var def = this.redefined();
if (def) {
this.mangled_name = def.mangled_name || def.name;
} else {
this.mangled_name = next_mangled_name(this, options);
}
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
if (cache) cache.set(this.name, this.mangled_name);
}
},
redefined: function() {
@@ -285,7 +286,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// ensure mangling works if `catch` reuses a scope variable
var redef = def.redefined();
if (redef) for (var s = node.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, redef);
if (!push_uniq(s.enclosed, redef)) break;
if (s === redef.scope) break;
}
} else if (node instanceof AST_SymbolConst) {
@@ -368,8 +369,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// pass 3: fix up any scoping issue with IE8
if (options.ie) self.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolCatch) {
var scope = node.thedef.defun;
if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
var def = node.thedef;
var scope = def.defun;
if (def.name != "arguments" && scope.name instanceof AST_SymbolLambda && scope.name.name == def.name) {
scope = scope.parent_scope.resolve();
}
redefine(node, scope);
@@ -479,7 +481,7 @@ AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
for (var s = this.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (!push_uniq(s.enclosed, def)) break;
if (!options) {
s._var_names = undefined;
} else {
@@ -621,14 +623,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
var lname = -1;
var redefined = [];
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LabeledStatement) {
// `lname` is incremented when we get to the `AST_Label`
var save_nesting = lname;
descend();
if (!options.v8 || !in_label(tw)) lname = save_nesting;
return true;
}
var save_nesting;
if (node instanceof AST_BlockScope) {
// `lname` is incremented when we get to the `AST_Label`
if (node instanceof AST_LabeledStatement) save_nesting = lname;
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
node.init.definitions.forEach(function(defn) {
defn.name.match_symbol(function(sym) {
@@ -674,6 +672,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
}));
}
to_mangle.forEach(mangle);
if (node instanceof AST_LabeledStatement && !(options.v8 && in_label(tw))) lname = save_nesting;
return true;
}
if (node instanceof AST_Label) {
@@ -706,7 +705,12 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
}
redefined.push(def);
def.references.forEach(reference);
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) {
reference(sym);
def.redefined = function() {
return redef;
};
}
return true;
function reference(sym) {

View File

@@ -127,8 +127,10 @@ function push_uniq(array, el) {
function string_template(text, props) {
return text.replace(/\{([^{}]+)\}/g, function(str, p) {
var value = props[p];
return value instanceof AST_Node ? value.print_to_string() : value;
var value = p == "this" ? props : props[p];
if (value instanceof AST_Node) return value.print_to_string();
if (value instanceof AST_Token) return value.file + ":" + value.line + "," + value.col;
return value;
});
}

View File

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

View File

@@ -60,8 +60,9 @@ function log() {
console.log("%s", tmpl.apply(null, arguments));
}
function make_code(ast, options) {
function make_code(ast, options, expression) {
var stream = U.OutputStream(options);
if (expression) ast = ast.clone(true).unwrap_expression();
ast.print(stream);
return stream.get();
}
@@ -69,9 +70,7 @@ function make_code(ast, options) {
function parse_test(file) {
var script = fs.readFileSync(file, "utf8");
try {
var ast = U.parse(script, {
filename: file
});
var ast = U.parse(script, { filename: file, module: "" });
} catch (e) {
console.error("Caught error while parsing tests in " + file);
console.error(e);
@@ -98,14 +97,14 @@ function parse_test(file) {
file: file,
line: node.start.line,
col: node.start.col,
code: make_code(node, { beautify: false })
code: make_code(node, { beautify: false }),
}));
}
function read_string(stat) {
if (stat.TYPE == "SimpleStatement") {
var body = stat.body;
switch(body.TYPE) {
switch (body.TYPE) {
case "String":
return body.value;
case "Array":
@@ -127,6 +126,17 @@ function parse_test(file) {
croak(node);
}
var name = node.left.name;
assert.ok([
"beautify",
"expression",
"mangle",
"options",
"rename",
].indexOf(name) >= 0, tmpl("Unsupported setting {name} [{line},{col}]", {
name: name,
line: node.start.line,
col: node.start.col,
}));
test[name] = evaluate(node.right);
return true;
}
@@ -142,7 +152,7 @@ function parse_test(file) {
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
name: label.name,
line: label.start.line,
col: label.start.col
col: label.start.col,
}));
var stat = node.body;
if (label.name == "expect_exact" || label.name == "node_version") {
@@ -155,12 +165,12 @@ function parse_test(file) {
var ctor = global[body.expression.name];
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
line: label.start.line,
col: label.start.col
col: label.start.col,
}));
test[label.name] = ctor.apply(null, body.args.map(function(node) {
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
line: label.start.line,
col: label.start.col
col: label.start.col,
}));
return node.value;
}));
@@ -180,9 +190,18 @@ function parse_test(file) {
// Try to reminify original input with standard options
// to see if it matches expect_stdout.
function reminify(orig_options, input_code, input_formatted, stdout) {
function reminify(expression, orig_options, input_code, input_formatted, stdout) {
for (var i = 0; i < minify_options.length; i++) {
var options = JSON.parse(minify_options[i]);
if (expression) {
if (!options.parse || typeof options.parse != "object") options.parse = {};
options.parse.expression = true;
if (options.compress == null) options.compress = {};
if (options.compress) {
if (typeof options.compress != "object") options.compress = {};
options.compress.expression = true;
}
}
[
"keep_fargs",
"keep_fnames",
@@ -212,7 +231,7 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
} else {
var toplevel = sandbox.has_toplevel(options);
var expected = stdout[toplevel ? 1 : 0];
var actual = sandbox.run_code(result.code, toplevel);
var actual = run_code(expression, result.code, toplevel);
if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
actual = expected;
}
@@ -247,18 +266,25 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
return true;
}
function run_code(expression, code, toplevel) {
return sandbox.run_code(expression ? "console.log(" + code + ");" : code, toplevel);
}
function test_case(test) {
log(" Running test [{name}]", { name: test.name });
U.AST_Node.enable_validation();
var output_options = test.beautify || {};
var expect;
if (test.expect) {
expect = make_code(to_toplevel(test.expect, test.mangle), output_options);
expect = to_toplevel(test.expect, test.mangle, test.expression);
expect = make_code(expect, output_options, test.expression);
} else {
expect = test.expect_exact;
}
var input = to_toplevel(test.input, test.mangle);
var input_code = make_code(input);
var input = to_toplevel(test.input, test.mangle, test.expression);
var input_code = make_code(input, {
keep_quoted_props: true,
}, test.expression);
var input_formatted = make_code(test.input, {
annotations: true,
beautify: true,
@@ -268,7 +294,7 @@ function test_case(test) {
});
try {
input.validate_ast();
U.parse(input_code);
U.parse(input_code, { expression: test.expression });
} catch (ex) {
log([
"!!! Cannot parse input",
@@ -294,8 +320,9 @@ function test_case(test) {
warnings_emitted.push(text);
}, /"INFO: /.test(expected_warnings));
}
var quoted_props;
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var quoted_props = test.mangle.properties.reserved;
quoted_props = test.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
@@ -310,9 +337,10 @@ function test_case(test) {
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (quoted_props) U.reserve_quoted_keys(input, quoted_props);
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
}
var output_code = make_code(output, output_options);
var output_code = make_code(output, output_options, test.expression);
U.AST_Node.log_function();
if (expect != output_code) {
log([
@@ -335,7 +363,7 @@ function test_case(test) {
// expect == output
try {
output.validate_ast();
U.parse(output_code);
U.parse(output_code, { expression: test.expression });
} catch (ex) {
log([
"!!! Test matched expected result but cannot parse output",
@@ -379,7 +407,7 @@ function test_case(test) {
}
}
if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = [ sandbox.run_code(input_code), sandbox.run_code(input_code, true) ];
var stdout = [ run_code(test.expression, input_code), run_code(test.expression, input_code, true) ];
var toplevel = sandbox.has_toplevel({
compress: test.options,
mangle: test.mangle
@@ -408,7 +436,7 @@ function test_case(test) {
});
return false;
}
actual = sandbox.run_code(output_code, toplevel);
actual = run_code(test.expression, output_code, toplevel);
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
log([
"!!! failed",
@@ -429,7 +457,7 @@ function test_case(test) {
});
return false;
}
if (!reminify(test.options, input_code, input_formatted, stdout)) {
if (!reminify(test.expression, test.options, input_code, input_formatted, stdout)) {
return false;
}
}
@@ -440,20 +468,30 @@ function tmpl() {
return U.string_template.apply(null, arguments);
}
function to_toplevel(input, mangle_options) {
function to_toplevel(input, mangle_options, expression) {
if (!(input instanceof U.AST_BlockStatement)) throw new Error("Unsupported input syntax");
var directive = true;
var offset = input.start.line;
var tokens = [];
var toplevel = new U.AST_Toplevel(input.transform(new U.TreeTransformer(function(node) {
input.walk(new U.TreeWalker(function(node) {
if (U.push_uniq(tokens, node.start)) node.start.line -= offset;
if (!directive || node === input) return;
if (U.push_uniq(tokens, node.end)) node.end.line -= offset;
}));
var toplevel;
if (!expression) {
var directive = true;
toplevel = new U.AST_Toplevel(input.transform(new U.TreeTransformer(function(node) {
if (!directive) return node;
if (node === input) return;
if (node instanceof U.AST_SimpleStatement && node.body instanceof U.AST_String) {
return new U.AST_Directive(node.body);
} else {
directive = false;
}
directive = false;
})));
} else if (input.body.length == 1) {
toplevel = input.body[0].wrap_expression();
} else {
throw new Error("Invalid expression");
}
toplevel.figure_out_scope(mangle_options);
return toplevel;
}

View File

@@ -668,6 +668,28 @@ single_use_recursive: {
node_version: ">=4"
}
inline_iife_within_arrow: {
options = {
arrows: true,
inline: true,
}
input: {
var f = () => console.log(function(a) {
return Math.ceil(a);
}(Math.random()));
f();
}
expect: {
var f = () => {
return console.log((a = Math.random(), Math.ceil(a)));
var a;
};
f();
}
expect_stdout: "1"
node_version: ">=4"
}
issue_4388: {
options = {
inline: true,
@@ -1073,7 +1095,7 @@ issue_5414_2: {
node_version: ">=4"
}
issue_5416: {
issue_5416_1: {
options = {
dead_code: true,
evaluate: true,
@@ -1095,10 +1117,11 @@ issue_5416: {
expect: {
var f = () => {
{
arguments = void 0;
console;
arguments = void 0,
console.log(arguments);
var arguments;
return;
}
};
f();
@@ -1106,3 +1129,133 @@ issue_5416: {
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5416_2: {
options = {
dead_code: true,
evaluate: true,
inline: true,
loops: true,
unused: true,
}
input: {
var f = () => {
while ((() => {
console;
var a = function g(arguments) {
while (console.log(arguments));
}();
})());
};
f();
}
expect: {
var f = () => {
{
console;
var arguments = void 0;
for (; console.log(arguments););
return;
}
};
f();
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5416_3: {
options = {
inline: true,
side_effects: true,
unused: true,
}
input: {
var f = () => {
(() => {
var a = function g(arguments) {
console.log(arguments);
}();
})();
};
f();
}
expect: {
var f = () => {
arguments = void 0,
console.log(arguments);
var arguments;
};
f();
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5416_4: {
options = {
arrows: true,
inline: true,
side_effects: true,
unused: true,
}
input: {
var f = () => {
(() => {
var a = function g(arguments) {
while (console.log(arguments));
}();
})();
};
f();
}
expect: {
var f = () => {
var arguments = void 0;
while (console.log(arguments));
return;
};
f();
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5495: {
input: {
console.log((() => {
"use strict";
return function() {
return this;
}();
})());
}
expect_exact: 'console.log((()=>{"use strict";return function(){return this}()})());'
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5653: {
options = {
arrows: true,
hoist_props: true,
passes: 2,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
console.log((a => {
a = { p: console };
return a++;
})());
}
expect: {
console.log((a => {
return console, +{};
})());
}
expect_stdout: "NaN"
node_version: ">=4"
}

View File

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

View File

@@ -529,6 +529,7 @@ inline_block_await: {
inline_block_await_async: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -1046,6 +1047,60 @@ collapse_vars_3: {
node_version: ">=8"
}
collapse_funarg_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
A = "FAIL";
var a = "PASS";
(async function({}, b) {
return b;
})(null, A = a);
console.log(A);
}
expect: {
A = "FAIL";
var a = "PASS";
(async function({}, b) {
return b;
})(null, A = a);
console.log(A);
}
expect_stdout: "PASS"
node_version: ">=8"
}
collapse_funarg_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
A = "FAIL";
B = "PASS";
(async function() {
console.log(function({}, a) {
return a;
}(null, A = B));
})();
console.log(A);
}
expect: {
A = "FAIL";
B = "PASS";
(async function() {
console.log(function({}, a) {
return a;
}(null, A = B));
})();
console.log(A);
}
expect_stdout: "PASS"
node_version: ">=8"
}
collapse_property_lambda: {
options = {
collapse_vars: true,
@@ -1293,6 +1348,21 @@ functions_inner_var: {
node_version: ">=8"
}
instanceof_lambda: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(42 instanceof async function() {});
}
expect: {
console.log(false);
}
expect_stdout: "false"
node_version: ">=8"
}
issue_4335_1: {
options = {
inline: true,
@@ -1748,8 +1818,8 @@ issue_4454_2: {
expect: {
function f(a) {
(async function(c = console.log(a)) {})();
var a = 42..toString();
console.log(a);
var b = 42..toString();
console.log(b);
}
f("PASS");
}
@@ -2427,80 +2497,6 @@ issue_5023_2: {
node_version: ">=8"
}
issue_5032_normal: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var a = log(a), c = a;
log(a);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5032_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5034: {
options = {
functions: true,
@@ -2752,6 +2748,7 @@ issue_5177: {
issue_5250: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2860,6 +2857,7 @@ issue_5298: {
issue_5305_1: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2893,6 +2891,7 @@ issue_5305_1: {
issue_5305_2: {
options = {
awaits: true,
inline: true,
}
input: {
@@ -2959,3 +2958,643 @@ issue_5305_3: {
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5456: {
options = {
inline: true,
merge_vars: true,
}
input: {
var a = true;
(function() {
(function(b, c) {
var d = async function() {
c = await null;
}();
var e = function() {
if (c)
console.log(typeof d);
while (b);
}();
})(function(i) {
return console.log("foo") && i;
}(a));
})();
}
expect: {
var a = true;
(function() {
b = (i = a, console.log("foo") && i),
d = async function() {
c = await null;
}(),
e = function() {
if (c) console.log(typeof d);
while (b);
}(),
void 0;
var b, c, d, e;
var i;
})();
}
expect_stdout: "foo"
node_version: ">=8"
}
issue_5478: {
options = {
side_effects: true,
}
input: {
A = {
get then() {
a = "FAIL";
},
};
var a = "PASS";
(async function() {
for (var b in "foo")
return void A;
})();
console.log(a);
}
expect: {
A = {
get then() {
a = "FAIL";
},
};
var a = "PASS";
(async function() {
for (var b in "foo")
return !A;
})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5493: {
options = {
collapse_vars: true,
reduce_vars: true,
}
input: {
(async function(a) {
var b = await [ 42 || b, a = b ];
console.log(a);
})();
}
expect: {
(async function(a) {
var b = await [ 42 || b, a = b ];
console.log(a);
})();
}
expect_stdout: "undefined"
node_version: ">=8"
}
issue_5506: {
options = {
dead_code: true,
}
input: {
console.log(function(a) {
(async function() {
a = null in (a = "PASS");
})();
return a;
}("FAIL"));
}
expect: {
console.log(function(a) {
(async function() {
a = null in (a = "PASS");
})();
return a;
}("FAIL"));
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_5528_1: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
await function() {
try {
return;
} finally {
console.log("foo");
}
}();
})();
console.log("bar");
}
expect: {
(async function() {
await function() {
try {
return;
} finally {
console.log("foo");
}
}();
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}
issue_5528_2: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
await function() {
try {
return 42;
} finally {
console.log("foo");
}
}();
})();
console.log("bar");
}
expect: {
(async function() {
await function() {
try {
return 42;
} finally {
console.log("foo");
}
}();
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}
issue_5528_3: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
await function() {
try {
FAIL;
} catch (e) {
return console.log("foo");
} finally {
console.log("bar");
}
}();
})();
console.log("baz");
}
expect: {
(async function() {
await function() {
try {
FAIL;
} catch (e) {
return console.log("foo");
} finally {
console.log("bar");
}
}();
})();
console.log("baz");
}
expect_stdout: [
"foo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5528_4: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
await function() {
try {
return {
then() {
console.log("foo");
},
};
} finally {
console.log("bar");
}
}();
})();
console.log("baz");
}
expect: {
(async function() {
await function() {
try {
return {
then() {
console.log("foo");
},
};
} finally {
console.log("bar");
}
}();
})();
console.log("baz");
}
expect_stdout: [
"bar",
"baz",
"foo",
]
node_version: ">=8"
}
issue_5634_1: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_1_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_2: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_2_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
await async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_3: {
options = {
awaits: true,
inline: true,
}
input: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5634_3_side_effects: {
options = {
awaits: true,
inline: true,
side_effects: true,
}
input: {
var a = "foo";
(async function() {
return async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
}();
})();
console.log(a);
}
expect: {
var a = "foo";
(async function() {
try {
return {
then(resolve) {
console.log("bar");
resolve();
console.log("baz");
},
};
} finally {
a = "moo";
}
})();
console.log(a);
}
expect_stdout: [
"moo",
"bar",
"baz",
]
node_version: ">=8"
}
issue_5692_1: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
(async function() {
for await (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=10"
}
issue_5692_2: {
options = {
awaits: true,
inline: true,
}
input: {
(async function() {
(async function() {
for (var k of []);
})();
console.log("foo");
})();
console.log("bar");
}
expect: {
(async function() {
for (var k of []);
console.log("foo");
})();
console.log("bar");
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}

View File

@@ -80,6 +80,25 @@ de_morgan_1c: {
expect_stdout: "true"
}
de_morgan_1d: {
options = {
booleans: true,
}
input: {
function f(a) {
return (a = false) || a;
}
console.log(f(null), f(42));
}
expect: {
function f(a) {
return a = !1;
}
console.log(f(null), f(42));
}
expect_stdout: "false false"
}
de_morgan_2a: {
options = {
booleans: true,
@@ -181,6 +200,31 @@ de_morgan_2d: {
]
}
de_morgan_2e: {
options = {
booleans: true,
conditionals: true,
}
input: {
function f(a, b) {
return (a && b) && b;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect: {
function f(a, b) {
return a && b;
}
console.log(f(null), f(null, {}));
console.log(f(42), f(42, {}));
}
expect_stdout: [
"null null",
"undefined {}",
]
}
de_morgan_3a: {
options = {
booleans: true,
@@ -762,3 +806,61 @@ issue_5228: {
}
expect_stdout: "true"
}
issue_5469: {
options = {
assignments: true,
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
pure_getters: "strict",
side_effects: true,
}
input: {
console.log(function f(a) {
a && 42[a = A && null];
}());
}
expect: {
console.log(function f(a) {
a && A,
0;
}());
}
expect_stdout: "undefined"
}
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
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -40,6 +40,22 @@ unsafe_comps: {
}
}
unsafe_in_instanceof: {
options = {
side_effects: true,
unsafe_comps: true,
}
input: {
var a;
42 in a;
f() instanceof "foo";
}
expect: {
var a;
f();
}
}
dont_change_in_or_instanceof_expressions: {
input: {
1 in 1;
@@ -259,6 +275,7 @@ issue_2857_3: {
issue_2857_4: {
options = {
comparisons: true,
conditionals: true,
}
input: {
function f(a, p) {
@@ -289,6 +306,7 @@ issue_2857_4: {
issue_2857_5: {
options = {
comparisons: true,
conditionals: true,
}
input: {
function f(a, p) {
@@ -512,6 +530,7 @@ nullish_assign: {
nullish_chain: {
options = {
comparisons: true,
conditionals: true,
}
input: {
var a;

View File

@@ -12,7 +12,7 @@ concat_1: {
var e = 1 + x() + 2 + "X" + 3 + "boo";
// be careful with concatentation with "\0" with octal-looking strings.
// be careful with concatenation with "\0" with octal-looking strings.
var f = "\0" + 360 + "\0" + 8 + "\0";
}
expect: {

File diff suppressed because it is too large Load Diff

View File

@@ -142,6 +142,80 @@ if_dead_branch: {
expect_stdout: "undefined"
}
retain_tail_1: {
options = {
conditionals: true,
}
input: {
function f(a) {
var b = "foo";
if (a) {
const b = "bar";
while (console.log("baz"));
console.log(b);
} else {
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect: {
function f(a) {
var b = "foo";
if (a) {
const b = "bar";
while (console.log("baz"));
console.log(b);
} else {
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect_stdout: true
}
retain_tail_2: {
options = {
conditionals: true,
}
input: {
function f(a) {
var b = "foo";
if (a) {
while (console.log("bar"));
console.log(b);
} else {
const b = "baz";
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect: {
function f(a) {
var b = "foo";
if (a) {
while (console.log("bar"));
console.log(b);
} else {
const b = "baz";
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect_stdout: true
}
merge_vars_1: {
options = {
merge_vars: true,
@@ -579,6 +653,37 @@ dead_block_after_return: {
expect_stdout: true
}
if_return_3: {
options = {
if_return: true,
}
input: {
var a = "PASS";
function f(b) {
if (console) {
const b = a;
return b;
} else
while (console.log("FAIL 1"));
return b;
}
console.log(f("FAIL 2"));
}
expect: {
var a = "PASS";
function f(b) {
if (console) {
const b = a;
return b;
} else
while (console.log("FAIL 1"));
return b;
}
console.log(f("FAIL 2"));
}
expect_stdout: true
}
do_if_continue_1: {
options = {
if_return: true,
@@ -1855,3 +1960,247 @@ issue_5338: {
}
expect_stdout: true
}
issue_5476: {
mangle = {
keep_fargs: true,
}
input: {
console.log(function(n) {
const a = 42;
}());
}
expect: {
console.log(function(n) {
const o = 42;
}());
}
expect_stdout: "undefined"
}
issue_5516: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(typeof function() {
try {} catch (a) {
(function f() {
a;
})();
}
{
const a = function() {};
return a;
}
}());
}
expect: {
console.log(typeof function() {
try {} catch (a) {
void a;
}
{
const a = function() {};
return a;
}
}());
}
expect_stdout: "function"
}
issue_5580_1: {
mangle = {}
input: {
"use strict";
console.log(function(a, b, c) {
try {
FAIL;
} catch (e) {
return function() {
var d = e, i, j;
{
const e = j;
}
return a;
}();
} finally {
const e = 42;
}
}("PASS"));
}
expect: {
"use strict";
console.log(function(r, n, t) {
try {
FAIL;
} catch (o) {
return function() {
var n = o, t, c;
{
const o = c;
}
return r;
}();
} finally {
const c = 42;
}
}("PASS"));
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5580_2: {
options = {
inline: true,
reduce_vars: true,
varify: true,
}
input: {
"use strict";
(function() {
try {
throw "PASS";
} catch (e) {
return function() {
console.log(e);
{
const e = "FAIL 1";
}
}();
} finally {
const e = "FAIL 2";
}
})();
}
expect: {
"use strict";
(function() {
try {
throw "PASS";
} catch (e) {
console.log(e);
{
const e = "FAIL 1";
}
return;
} finally {
var e = "FAIL 2";
}
})();
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5591: {
options = {
dead_code: true,
if_return: true,
}
input: {
"use strict";
function f(a) {
switch (console.log("foo")) {
case console.log("bar"):
if (console.log("baz"))
return;
else {
const a = 42;
return;
}
break;
case null:
FAIL;
}
}
f();
}
expect: {
"use strict";
function f(a) {
switch (console.log("foo")) {
case console.log("bar"):
if (console.log("baz"))
return;
else {
const a = 42;
return;
}
case null:
FAIL;
}
}
f();
}
expect_stdout: [
"foo",
"bar",
"baz",
]
node_version: ">=4"
}
issue_5656: {
options = {
collapse_vars: true,
merge_vars: true,
}
input: {
console.log(function(a) {
var b = a;
b++;
{
const a = b;
}
}());
}
expect: {
console.log(function(a) {
var b = a;
{
const a = ++b;
}
}());
}
expect_stdout: true
}
issue_5660: {
options = {
merge_vars: true,
side_effects: true,
}
input: {
function f() {
try {
a;
var b;
return b;
} catch (e) {
var a = "FAIL";
const b = null;
return a;
}
}
console.log(f());
}
expect: {
function f() {
try {
var b;
return b;
} catch (e) {
var a = "FAIL";
const b = null;
return a;
}
}
console.log(f());
}
expect_stdout: true
}

View File

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

View File

@@ -180,6 +180,26 @@ collapse_arg_sequence: {
node_version: ">=6"
}
collapse_in_arg: {
options = {
collapse_vars: true,
keep_fargs: false,
unused: true,
}
input: {
(function(a, b = a) {
b("PASS");
})(console.log);
}
expect: {
(function(a) {
a("PASS");
})(console.log);
}
expect_stdout: "PASS"
node_version: ">=6"
}
collapse_value_1: {
options = {
collapse_vars: true,
@@ -541,7 +561,7 @@ inline_side_effects_2: {
}
expect: {
var a = 42;
[ [].e = --a ] = [ console ];
[ [][0] = --a ] = [ console ];
console.log(a);
}
expect_stdout: "42"
@@ -648,6 +668,8 @@ drop_fargs: {
hoist_vars: {
options = {
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
var a = "PASS";
@@ -655,8 +677,7 @@ hoist_vars: {
console.log(a, b);
}
expect: {
var a = "PASS";
var [ b = 42 ] = [];
var a = "PASS", [ b = 42 ] = [];
console.log(a, b);
}
expect_stdout: "PASS 42"
@@ -1170,6 +1191,49 @@ mangle_arrow_2_toplevel: {
node_version: ">=6.9.3"
}
collapse_preceding_simple_arg: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = "foo";
console.log(function(b, c = "bar") {
return b + c;
}(a, a));
}
expect: {
var a = "foo";
console.log(function(b, c = "bar") {
return a + c;
}(0, a));
}
expect_stdout: "foofoo"
node_version: ">=6"
}
drop_preceding_simple_arg: {
options = {
collapse_vars: true,
keep_fargs: false,
unused: true,
}
input: {
var a = "foo";
console.log(function(b, c = "bar") {
return b + c;
}(a, a));
}
expect: {
var a = "foo";
console.log(function(c = "bar") {
return a + c;
}(a));
}
expect_stdout: "foofoo"
node_version: ">=6"
}
issue_4444: {
options = {
collapse_vars: true,
@@ -1558,7 +1622,7 @@ issue_4502_4: {
(function(a, b = console.log("FAIL")) {})(..."" + console.log(42));
}
expect: {
[ , [].e = console.log("FAIL") ] = [ ..."" + console.log(42) ];
[ , [][0] = console.log("FAIL") ] = [ ..."" + console.log(42) ];
}
expect_stdout: "42"
node_version: ">=6"
@@ -1655,7 +1719,7 @@ issue_4540: {
node_version: ">=6"
}
issue_4548: {
issue_4548_1: {
options = {
merge_vars: true,
toplevel: true,
@@ -1681,6 +1745,32 @@ issue_4548: {
node_version: ">=6"
}
issue_4548_2: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
A = "foo";
var a = A;
var [ b = c = "bar" ] = [ console, console.log(a) ];
console.log(c);
var c;
}
expect: {
A = "foo";
var a = A;
var [ b = c = "bar" ] = [ console, console.log(a) ];
console.log(c);
var c;
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=6"
}
issue_4588_1_unused: {
options = {
unused: true,
@@ -2023,7 +2113,7 @@ issue_5246_1: {
}
expect_stdout: "PASS"
expect_warnings: [
"INFO: Dropping unused default argument {}=42 [test/compress/default-values.js:1,29]",
"INFO: Dropping unused default argument {} [test/compress/default-values.js:1,29]",
]
node_version: ">=6"
}
@@ -2183,7 +2273,7 @@ issue_5340_2: {
}
expect: {
var a;
[ [].e = 0 ] = [ ({ p: a } = true).q ];
[ [][0] = 0 ] = [ ({ p: a } = true).q ];
console.log(a);
}
expect_stdout: "undefined"
@@ -2239,3 +2329,743 @@ issue_5407: {
]
node_version: ">=6"
}
issue_5444_1: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
var a = 42;
var b = function({} = setImmediate(function() {
console.log(a++);
})) {
return this;
}();
console.log(typeof b);
}
expect: {
var a = 42;
var b = function({} = setImmediate(function() {
console.log(a++);
})) {
return this;
}();
console.log(typeof b);
}
expect_stdout: [
"object",
"42",
]
node_version: ">=6"
}
issue_5444_2: {
options = {
merge_vars: true,
}
input: {
function f(a, b = a++) {
return b;
}
console.log(f("FAIL") || "PASS");
}
expect: {
function f(a, b = a++) {
return b;
}
console.log(f("FAIL") || "PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5444_3: {
options = {
merge_vars: true,
}
input: {
function f(a, b = function(c = a *= this) {
return c;
}()) {
return b;
}
console.log(f("FAIL") || "PASS");
}
expect: {
function f(a, b = function(c = a *= this) {
return c;
}()) {
return b;
}
console.log(f("FAIL") || "PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5448_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(a = typeof console.log) {
do {
var b = [ ...a ];
} while (console.log("PASS"));
})();
}
expect: {
(function(a = console.log) {
do {} while (console.log("PASS"));
})();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5448_2: {
options = {
keep_fargs: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a = typeof console) {
do {
var b = [ ...a ];
} while (console.log("PASS"));
})();
}
expect: {
(function(a = 0) {
do {} while (console.log("PASS"));
})();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5448_3: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var [ a = typeof console ] = [ void console.log("PASS") ];
var b = [ ...a ];
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5448_4: {
options = {
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var { p: a = typeof console } = { p: void console.log("PASS") };
var b = [ ...a ];
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5463: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
if (console.log("PASS"))
var a = void 0,
b = void 0,
b = ([ a = FAIL ] = b && b);
}
expect: {
var a, b, b;
console.log("PASS") && (
b = a = void 0,
b = [a = FAIL] = a
);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5465: {
options = {
inline: true,
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a, b) {
(function(c = b = "FAIL 2") {
this && console.log(b || "PASS");
})(42 - a && a);
}
f("FAIL 1");
}
expect: {
a = "FAIL 1",
void function(c = b = "FAIL 2") {
this && console.log(b || "PASS");
}(42 - a && a);
var a, b;
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5485: {
options = {
comparisons: true,
}
input: {
(function f(f, a = console.log(void 0 === f ? "PASS" : "FAIL")) {})();
}
expect: {
(function f(f, a = console.log(void 0 === f ? "PASS" : "FAIL")) {})();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_1_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_1_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_2_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f([ b ] = []) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;) {
var [ [] = [] ] = [];
throw "PASS";
}
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_2_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f([ b ] = []) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;) {
var [ [ , ] = [] ] = [];
throw "PASS";
}
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_3_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42, c = null) {
c;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_3_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42, c = null) {
c;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_4_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42, [ c ] = []) {
c;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;) {
var [ [] = [] ] = [];
throw "PASS";
}
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_4_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b = 42, [ c ] = []) {
c;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;) {
var [ [] = [] ] = [];
throw "PASS";
}
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5536: {
options = {
inline: true,
keep_fargs: true,
unused: true,
}
input: {
(function*() {
(([], a = 42) => {})([]);
console.log(typeof a);
})().next();
}
expect: {
(function*() {
[ , [][0] = 0 ] = [ [] ],
void 0;
console.log(typeof a);
})().next();
}
expect_stdout: "undefined"
node_version: ">=6"
}
issue_5566_1: {
options = {
unused: true,
}
input: {
(function(a, f = function() {
return a;
}) {
var a = "foo";
console.log(a, f());
})("bar");
}
expect: {
(function(a, f = function() {
return a;
}) {
var a = "foo";
console.log(a, f());
})("bar");
}
expect_stdout: "foo bar"
node_version: ">=6"
}
issue_5566_2: {
options = {
inline: true,
reduce_vars: true,
}
input: {
(function(a, f = function() {
return a;
}) {
function a() {}
console.log(typeof a, typeof f());
})(42);
}
expect: {
(function(a, f = function() {
return a;
}) {
function a() {}
console.log(typeof a, typeof f());
})(42);
}
expect_stdout: "function number"
node_version: ">=6"
}
issue_5566_3: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(a, f = function() {
return a;
}) {
function a() {}
console.log(typeof a, typeof f());
})(42);
}
expect: {
(function(a, f = function() {
return a;
}) {
function a() {}
console.log(typeof a, typeof f());
})(42);
}
expect_stdout: "function number"
node_version: ">=6"
}
issue_5566_4: {
options = {
collapse_vars: true,
unused: true,
}
input: {
(function(a, b = function() {
return a;
}) {
var a = 0;
b()("PASS");
})(console.log);
}
expect: {
(function(a, b = function() {
return a;
}) {
var a = 0;
b()("PASS");
})(console.log);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5566_5: {
options = {
hoist_vars: true,
}
input: {
(function(a, f = function() {
return a;
}) {
var a = "foo";
var b;
console.log(a, f());
})("bar");
}
expect: {
(function(a, f = function() {
return a;
}) {
var a, b;
a = "foo";
console.log(a, f());
})("bar");
}
expect_stdout: "foo bar"
node_version: ">=6"
}
issue_5651: {
options = {
ie: true,
unused: true,
}
input: {
console.log(function arguments(a = "FAIL") {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}());
}
expect: {
console.log(function arguments(a = "FAIL") {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}());
}
expect_stdout: true
node_version: ">=6"
}

View File

@@ -472,6 +472,93 @@ funarg_collapse_vars_3: {
node_version: ">=6"
}
funarg_collapse_vars_4: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = "PASS";
(function(b, { log: c }) {
c(b);
})(a, console);
}
expect: {
var a = "PASS";
(function(b, { log: c }) {
c(a);
})(0, console);
}
expect_stdout: "PASS"
node_version: ">=6"
}
funarg_collapse_vars_5: {
options = {
collapse_vars: true,
unused: true,
}
input: {
A = "FAIL";
B = "PASS";
try {
console.log(function({}, a) {
return a;
}(null, A = B));
} catch (e) {}
console.log(A);
}
expect: {
A = "FAIL";
B = "PASS";
try {
console.log(function({}, a) {
return a;
}(null, A = B));
} catch (e) {}
console.log(A);
}
expect_stdout: "PASS"
node_version: ">=6"
}
funarg_collapse_vars_6: {
options = {
collapse_vars: true,
unused: true,
}
input: {
A = "FAIL";
B = "PASS";
function f() {
console.log(function({}, a) {
return a;
}(null, A = B));
}
try {
f();
} catch (e) {
console.log(A);
}
}
expect: {
A = "FAIL";
B = "PASS";
function f() {
console.log(function({}, a) {
return a;
}(null, A = B));
}
try {
f();
} catch (e) {
console.log(A);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
funarg_reduce_vars_1: {
options = {
reduce_vars: true,
@@ -1219,7 +1306,7 @@ keep_reference: {
}
expect: {
var a = [ {}, 42 ];
var [ b ] = a;
var b = a[0];
console.log(a[0] === b ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
@@ -1565,6 +1652,8 @@ fn_name_unused: {
hoist_vars: {
options = {
hoist_vars: true,
join_vars: true,
unused: true,
}
input: {
var a = "PASS";
@@ -1572,8 +1661,7 @@ hoist_vars: {
console.log(a, b);
}
expect: {
var a = "PASS";
var [ b ] = [ 42 ];
var a = "PASS", b = [ 42 ][0];
console.log(a, b);
}
expect_stdout: "PASS 42"
@@ -1649,6 +1737,23 @@ singleton_side_effects: {
node_version: ">=6"
}
mangle_properties: {
mangle = {
properties: {
domprops: true,
},
}
input: {
function f({ p: a }) {
return a;
}
console.log(f({ p: "PASS" }));
}
expect_exact: 'function f({n}){return n}console.log(f({n:"PASS"}));'
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4280: {
options = {
evaluate: true,
@@ -1815,8 +1920,8 @@ issue_4288: {
console.log(typeof b);
}()]: a,
}) {
var b = a;
b++;
var a = a;
a++;
}
f(0);
}
@@ -1848,8 +1953,8 @@ issue_4294: {
}) {}({
[a]: 0,
});
var a = A;
console.log(a);
var b = A;
console.log(b);
})();
}
expect_stdout: "PASS"
@@ -1989,17 +2094,16 @@ issue_4312: {
console.log(a);
}
expect: {
var a;
b = "PASS",
c = "FAIL",
[
{
[a = b]: d,
[c = b]: d,
},
] = [ c && c ],
void 0;
var b, c, d;
console.log(a);
console.log(c);
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -3020,6 +3124,7 @@ issue_5074_method_pure_getters: {
issue_5085_1: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -3032,8 +3137,7 @@ issue_5085_1: {
}
expect: {
var a = "PASS";
var b = [ 42 ][0];
b;
42;
console.log(a);
}
expect_stdout: "PASS"
@@ -3043,6 +3147,7 @@ issue_5085_1: {
issue_5085_2: {
options = {
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unsafe: true,
@@ -3059,7 +3164,7 @@ issue_5085_2: {
expect: {
var a = "PASS";
(function(b) {
b = [ 42 ][0];
0;
})();
console.log(a);
}
@@ -3400,7 +3505,7 @@ issue_5222: {
node_version: ">=6"
}
issue_5288: {
issue_5288_1: {
options = {
conditionals: true,
inline: true,
@@ -3420,7 +3525,37 @@ issue_5288: {
}() ]));
}
expect: {
while (console ? console.log("PASS") : 0, void 0);
while (function() {
if (console)
console.log("PASS");
}(), void 0);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5288_2: {
options = {
conditionals: true,
inline: true,
keep_fargs: false,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
while (function([]) {}([ function f() {
if (console)
return console.log("PASS");
else {
let a = 0;
}
}() ]));
}
expect: {
while (console && console.log("PASS"), void 0);
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -3466,7 +3601,7 @@ issue_5314_2: {
A = this;
new function() {
[ {
[console.log(this === A ? "FAIL" : "PASS")]: [].e,
[console.log(this === A ? "FAIL" : "PASS")]: [][0],
} ] = [ 42 ];
}();
}
@@ -3566,3 +3701,188 @@ issue_5423: {
expect_stdout: "function"
node_version: ">=6"
}
issue_5454: {
options = {
hoist_props: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f(a) {
var a = 42, a = {
p: [ a ] = [],
};
return "PASS";
}
console.log(f());
}
expect: {
console.log(function(a) {
a = 42, a = {
p: [ a ] = [],
};
return "PASS";
}());
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5485: {
options = {
comparisons: true,
}
input: {
(function f({
p: f,
[console.log(void 0 === f ? "PASS" : "FAIL")]: a,
}) {})(42);
}
expect: {
(function f({
p: f,
[console.log(void 0 === f ? "PASS" : "FAIL")]: a,
}) {})(42);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f([ b ]) {
b;
throw "PASS";
})([]);
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f([ b ]) {
b;
throw "PASS";
})([]);
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5573: {
options = {
collapse_vars: true,
}
input: {
var log = console.log;
var a = "FAIL";
(function([ { [log(a)]: b } ]) {
A = 42;
})((a = "PASS", [ {} ]));
log(a, A);
}
expect: {
var log = console.log;
var a = "FAIL";
(function([ { [log(a)]: b } ]) {
A = 42;
})((a = "PASS", [ {} ]));
log(a, A);
}
expect_stdout: [
"PASS",
"PASS 42",
]
node_version: ">=6"
}
issue_5651: {
options = {
ie: true,
unused: true,
}
input: {
console.log(function arguments({}) {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}("PASS"));
}
expect: {
console.log(function arguments({}) {
try {} catch (arguments) {
var arguments;
}
return arguments[0];
}("PASS"));
}
expect_stdout: true
node_version: ">=6"
}

View File

@@ -131,19 +131,34 @@ valid_after_invalid_2: {
}
issue_5368_1: {
expression = true
options = {
directives: true,
expression: true,
}
input: {
"foo";
}
expect: {
"foo";
"foo"
}
expect_exact: '"foo"'
expect_stdout: "foo"
}
issue_5368_2: {
expression = true
options = {
directives: true,
expression: true,
}
input: {
(function() {
"foo";
})()
}
expect_exact: "function(){}()"
expect_stdout: "undefined"
}
issue_5368_3: {
options = {
directives: true,
expression: true,

View File

@@ -409,6 +409,15 @@ drop_toplevel_retain: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_retain_array: {
@@ -442,6 +451,15 @@ drop_toplevel_retain_array: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_retain_regex: {
@@ -471,6 +489,15 @@ drop_toplevel_retain_regex: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_all_retain: {
@@ -501,6 +528,15 @@ drop_toplevel_all_retain: {
a = 2;
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
"INFO: Dropping unused function g [test/compress/drop-unused.js:8,17]",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_funcs_retain: {
@@ -532,6 +568,12 @@ drop_toplevel_funcs_retain: {
function g() {}
console.log(b = 3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"WARN: Dropping unused function h [test/compress/drop-unused.js:9,17]",
]
}
drop_toplevel_vars_retain: {
@@ -564,6 +606,13 @@ drop_toplevel_vars_retain: {
function h() {}
console.log(3);
}
expect_stdout: "3"
expect_warnings: [
"INFO: Retaining variable a",
"INFO: Retaining variable f",
"INFO: Dropping unused variable b [test/compress/drop-unused.js:1,15]",
"INFO: Dropping unused variable c [test/compress/drop-unused.js:1,22]",
]
}
drop_toplevel_keep_assign: {
@@ -671,6 +720,76 @@ iife: {
}
}
drop_instanceof: {
options = {
booleans: true,
toplevel: true,
unused: true,
}
input: {
function f() {}
console.log({} instanceof f, Math instanceof f);
}
expect: {
console.log(!1, (Math, !1));
}
expect_stdout: "false false"
}
keep_instanceof_1: {
options = {
toplevel: true,
unused: true,
}
input: {
function f() {}
var f;
console.log({} instanceof f, Math instanceof f);
}
expect: {
function f() {}
var f;
console.log({} instanceof f, Math instanceof f);
}
expect_stdout: "false false"
}
keep_instanceof_2: {
options = {
toplevel: true,
unused: true,
}
input: {
function f() {}
var f = Object;
console.log({} instanceof f, Math instanceof f);
}
expect: {
function f() {}
var f = Object;
console.log({} instanceof f, Math instanceof f);
}
expect_stdout: "true true"
}
keep_instanceof_3: {
options = {
toplevel: true,
unused: true,
}
input: {
f = Object;
function f() {}
console.log({} instanceof f, Math instanceof f);
}
expect: {
f = Object;
function f() {}
console.log({} instanceof f, Math instanceof f);
}
expect_stdout: "true true"
}
issue_1539: {
options = {
collapse_vars: true,
@@ -1759,7 +1878,7 @@ issue_2846: {
var c = function(a, b) {
a = 0;
b && b(a);
return a++;
return +a;
}();
console.log(c);
}
@@ -2857,14 +2976,12 @@ issue_4025: {
console.log(a, b, d);
}
expect: {
var c = 0;
try {
console.log(c);
console.log(0);
} finally {
var d = c + 1;
c = 0;
0;
}
console.log(1, 1, d);
console.log(1, 1, 1);
}
expect_stdout: [
"0",
@@ -3577,7 +3694,7 @@ issue_5224: {
(function() {
var a = "FAIL 1";
null;
a = console.log(a);
console.log(a);
})(function() {
console.log(1 / 0);
a;
@@ -3615,3 +3732,85 @@ issue_5271: {
}
expect_stdout: "42"
}
issue_5533_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
}
issue_5533_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(b) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
}

View File

@@ -907,6 +907,20 @@ chained_side_effects: {
]
}
instanceof_lambda: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(42 instanceof function() {});
}
expect: {
console.log(false);
}
expect_stdout: "false"
}
issue_1649: {
options = {
evaluate: true,
@@ -3376,3 +3390,29 @@ issue_5380: {
}
expect_stdout: "PASS"
}
issue_5558: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
sequences: true,
toplevel: true,
}
input: {
var a = 99, b = 0;
a++;
b++;
b += a;
b *= a;
b += a;
console.log(a);
}
expect: {
var a = 99, b = 0;
b++,
b = (b += ++a) * a + a,
console.log(a);
}
expect_stdout: "100"
}

View File

@@ -109,6 +109,17 @@ foreign: {
expect_exact: 'export*from"foo";export{}from"bar";export*as a from"baz";export{default}from"moo";export{b,c as case,default as delete,d}from"moz";'
}
non_identifiers: {
beautify = {
quote_style: 3,
}
input: {
export * as "42" from 'foo';
export { '42', "delete" as 'foo' } from "bar";
}
expect_exact: "export*as\"42\"from'foo';export{'42',delete as foo}from\"bar\";"
}
same_quotes: {
beautify = {
beautify: true,
@@ -417,6 +428,46 @@ hoist_funs: {
expect_exact: "export function f(){}export default async function*g(){}"
}
instanceof_default_class: {
options = {
toplevel: true,
unused: true,
}
input: {
export default class A {
f(a) {
return a instanceof A;
}
}
}
expect: {
export default class A {
f(a) {
return a instanceof A;
}
}
}
}
instanceof_default_function: {
options = {
toplevel: true,
unused: true,
}
input: {
export default function f() {
if (!(this instanceof f))
throw new Error("must instantiate");
}
}
expect: {
export default function f() {
if (!(this instanceof f))
throw new Error("must instantiate");
}
}
}
issue_4742_join_vars_1: {
options = {
join_vars: true,
@@ -496,3 +547,36 @@ issue_4766: {
export var a = "bar";
}
}
issue_5444: {
options = {
unused: true,
}
input: {
export var a = (console, console);
}
expect: {
console;
export var a = console;
}
}
issue_5628: {
options = {
unused: true,
}
input: {
var a;
export default function f() {
for (a in 42);
}
console.log(a);
}
expect: {
var a;
export default function f() {
for (a in 42);
}
console.log(a);
}
}

View File

@@ -629,7 +629,7 @@ inline_binary_and: {
return void "moo";
return;
} else
return;
return void 0;
}());
}
expect_stdout: [
@@ -5512,6 +5512,40 @@ substitute_use_strict: {
]
}
substitute_assignment: {
options = {
evaluate: true,
inline: true,
passes: 2,
properties: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f(a, b, c) {
a[b] = c;
}
var o = {};
f(o, 42, null);
f(o, "foo", "bar");
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {};
o[42] = null;
o.foo = "bar";
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"42 null",
"foo bar",
]
}
issue_3833_1: {
options = {
inline: 3,
@@ -5582,7 +5616,7 @@ issue_3835: {
return f();
})();
}
expect_stdout: true
expect_stdout: RangeError("Maximum call stack size exceeded")
}
issue_3836_1: {
@@ -7835,7 +7869,7 @@ issue_5249_1: {
while (console.log("FAIL 2"));
return;
} else
return;
return void 0;
throw "FAIL 3";
}());
}
@@ -8398,3 +8432,311 @@ issue_5409: {
}
expect_stdout: "undefined"
}
mixed_mode_inline_1: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
return this;
}
console.log(function() {
return f();
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function() {
return this;
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
mixed_mode_inline_1_strict: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {
return this;
}
console.log(function() {
return f();
}() ? "FAIL" : "PASS");
}
expect: {
"use strict";
console.log(function() {
return this;
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
mixed_mode_inline_2: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
"use strict";
return this;
}
console.log(function() {
return f();
}() ? "FAIL" : "PASS");
}
expect: {
console.log(function() {
"use strict";
return this;
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
mixed_mode_inline_2_strict: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {
"use strict";
return this;
}
console.log(function() {
return f();
}() ? "FAIL" : "PASS");
}
expect: {
"use strict";
console.log(function() {
return this;
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
mixed_mode_inline_3: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
return this;
}
console.log(function() {
"use strict";
return f();
}() ? "PASS" : "FAIL");
}
expect: {
function f() {
return this;
}
console.log(function() {
"use strict";
return f();
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
mixed_mode_inline_3_strict: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {
return this;
}
console.log(function() {
"use strict";
return f();
}() ? "FAIL" : "PASS");
}
expect: {
"use strict";
console.log(function() {
return this;
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
mixed_mode_inline_4: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
"use strict";
return this;
}
console.log(function() {
"use strict";
return f();
}() ? "FAIL" : "PASS");
}
expect: {
console.log(function() {
"use strict";
return function() {
"use strict";
return this;
}();
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
mixed_mode_inline_4_strict: {
options = {
directives: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
function f() {
"use strict";
return this;
}
console.log(function() {
"use strict";
return f();
}() ? "FAIL" : "PASS");
}
expect: {
"use strict";
console.log(function() {
return this;
}() ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
module_inline: {
options = {
inline: true,
module: true,
reduce_vars: true,
}
input: {
var a = f;
function f() {
return a;
}
console.log(f() === a);
}
expect: {
var a = f;
function f() {
return a;
}
console.log(a === a);
}
expect_stdout: "true"
}
single_use_inline_collision: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "PASS";
(function() {
var f = function() {
while (console.log(a));
};
(function() {
(function() {
f();
})();
(function(a) {
a || a("FAIL");
})(console.log);
})();
})();
}
expect: {
var a = "PASS";
(function() {
(function() {
while (console.log(a));
return;
})();
(function(a) {
a || a("FAIL");
})(console.log);
return;
})();
}
expect_stdout: "PASS"
}
issue_5692: {
options = {
inline: true,
}
input: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect: {
(function() {
while (console.log("PASS"))
if (console)
return;
})();
}
expect_stdout: "PASS"
}

View File

@@ -462,6 +462,11 @@ issue_2473_1: {
var x = {};
var y = [];
}
expect_warnings: [
"INFO: Retaining variable x",
"INFO: Retaining variable y",
"WARN: Dropping unused variable z [test/compress/hoist_props.js:3,12]",
]
}
issue_2473_2: {
@@ -484,6 +489,11 @@ issue_2473_2: {
var x = {};
var y = [];
}
expect_warnings: [
"INFO: Retaining variable x",
"INFO: Retaining variable y",
"WARN: Dropping unused variable z [test/compress/hoist_props.js:3,12]",
]
}
issue_2473_3: {
@@ -509,6 +519,9 @@ issue_2473_3: {
console.log(o.a, o.b);
}
expect_stdout: "1 2"
expect_warnings: [
"INFO: Retaining variable o",
]
}
issue_2473_4: {
@@ -535,6 +548,9 @@ issue_2473_4: {
})();
}
expect_stdout: "1 2"
expect_warnings: [
"INFO: Dropping unused variable o [test/compress/hoist_props.js:2,16]",
]
}
issue_2508_1: {
@@ -1176,3 +1192,51 @@ issue_5182: {
"42",
]
}
issue_5441: {
options = {
hoist_props: true,
passes: 2,
reduce_vars: true,
side_effects: true,
}
input: {
console.log(function(a) {
(function() {
a = { p: this };
})();
return typeof a;
}());
}
expect: {
console.log(function(a) {
(function() {
a_p = this;
})();
var a_p;
return typeof {};
}());
}
expect_stdout: "object"
}
issue_5498: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
__proto__: 42,
};
while (console.log(typeof o.__proto__));
}
expect: {
var o = {
__proto__: 42,
};
while (console.log(typeof o.__proto__));
}
expect_stdout: "object"
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,17 @@ default_keys: {
expect_exact: 'import foo,{bar}from"baz";'
}
non_identifiers: {
beautify = {
quote_style: 3,
}
input: {
import { '42' as foo } from "bar";
import { "foo" as bar } from 'baz';
}
expect_exact: "import{'42'as foo}from\"bar\";import{foo as bar}from'baz';"
}
dynamic: {
input: {
(async a => await import(a))("foo").then(bar);
@@ -129,12 +140,12 @@ mangle: {
}
input: {
import foo, { bar } from "baz";
consoe.log(moo);
console.log(moo);
import * as moo from "moz";
}
expect: {
import o, { bar as m } from "baz";
consoe.log(r);
console.log(r);
import * as r from "moz";
}
}
@@ -146,12 +157,12 @@ rename_mangle: {
}
input: {
import foo, { bar } from "baz";
consoe.log(moo);
console.log(moo);
import * as moo from "moz";
}
expect: {
import o, { bar as m } from "baz";
consoe.log(r);
console.log(r);
import * as r from "moz";
}
}
@@ -227,3 +238,33 @@ issue_4708_2: {
import a from "foo";
}
}
pr_5550_1: {
input: {
if (console)
import("foo");
else
import.meta.url.replace(/bar/g, console.log);
}
expect: {
if (console)
import("foo");
else
import.meta.url.replace(/bar/g, console.log);
}
}
pr_5550_2: {
input: {
L: {
import("foo");
import.meta.url.replace(/bar/g, console.log);
}
}
expect: {
L: {
import("foo");
import.meta.url.replace(/bar/g, console.log);
}
}
}

View File

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

View File

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

View File

@@ -53,11 +53,21 @@ mangle_props: {
);
}
expect_stdout: "1 1 1 2 2 2 3 3 3 4 4 4 5 5"
expect_warnings: [
"INFO: Preserving reserved property undefined",
"INFO: Preserving reserved property NaN",
"INFO: Preserving reserved property Infinity",
"INFO: Preserving reserved property -Infinity",
"INFO: Preserving reserved property null",
"INFO: Preserving reserved property log",
]
}
numeric_literal: {
mangle = {
properties: true,
properties: {
domprops: true,
},
}
beautify = {
beautify: true,
@@ -106,11 +116,19 @@ numeric_literal: {
"4 5 4 4",
"8 7 8",
]
expect_warnings: [
"INFO: Mapping property 0x25 to o",
"INFO: Mapping property 1E42 to b",
"INFO: Preserving reserved property log",
]
}
identifier: {
mangle = {
properties: true,
properties: {
builtins: true,
domprops: true,
},
}
input: {
var obj = {
@@ -209,37 +227,37 @@ identifier: {
B: 28,
C: 29,
D: 30,
F: 31,
G: 32,
false: 33,
null: 34,
true: 35,
H: 36,
I: 37,
J: 38,
K: 39,
L: 40,
M: 41,
N: 42,
O: 43,
P: 44,
Q: 45,
R: 46,
S: 47,
T: 48,
U: 49,
V: 50,
W: 51,
X: 52,
Y: 53,
Z: 54,
$: 55,
_: 56,
ee: 57,
te: 58,
ne: 59,
ae: 60,
ie: 61,
E: 31,
F: 32,
G: 33,
H: 34,
I: 35,
J: 36,
K: 37,
L: 38,
M: 39,
N: 40,
O: 41,
P: 42,
Q: 43,
R: 44,
S: 45,
T: 46,
U: 47,
V: 48,
W: 49,
X: 50,
Y: 51,
Z: 52,
$: 53,
_: 54,
ee: 55,
te: 56,
ne: 57,
ae: 58,
ie: 59,
oe: 60,
re: 61,
};
}
}

View File

@@ -108,6 +108,7 @@ safe_undefined: {
}
negate_iife_3: {
expression = true
options = {
conditionals: true,
expression: true,
@@ -123,6 +124,7 @@ negate_iife_3: {
}
negate_iife_3_off: {
expression = true
options = {
conditionals: true,
expression: true,
@@ -203,6 +205,7 @@ negate_iife_5_off: {
}
issue_1254_negate_iife_true: {
expression = true
options = {
expression: true,
inline: true,
@@ -215,11 +218,12 @@ issue_1254_negate_iife_true: {
};
})()();
}
expect_exact: 'void console.log("test");'
expect_exact: 'void console.log("test")'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
expression = true
options = {
expression: true,
inline: true,
@@ -232,7 +236,7 @@ issue_1254_negate_iife_nested: {
};
})()()()()();
}
expect_exact: '(void console.log("test"))()()();'
expect_exact: '(void console.log("test"))()()()'
}
negate_iife_issue_1073: {

View File

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

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

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

View File

@@ -68,6 +68,7 @@ drop_console_2: {
}
drop_value: {
expression = true
options = {
expression: true,
side_effects: true,
@@ -106,6 +107,7 @@ wrongly_optimized: {
}
negate_iife_1: {
expression = true
options = {
expression: true,
negate_iife: true,
@@ -119,6 +121,7 @@ negate_iife_1: {
}
negate_iife_3: {
expression = true
options = {
conditionals: true,
expression: true,
@@ -133,6 +136,7 @@ negate_iife_3: {
}
negate_iife_3_off: {
expression = true
options = {
conditionals: true,
expression: true,
@@ -215,6 +219,7 @@ negate_iife_5_off: {
}
issue_1254_negate_iife_true: {
expression = true
options = {
expression: true,
negate_iife: true,
@@ -226,11 +231,12 @@ issue_1254_negate_iife_true: {
};
})()();
}
expect_exact: '(function(){return function(){console.log("test")}})()();'
expect_exact: 'function(){return function(){console.log("test")}}()()'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
expression = true
options = {
expression: true,
negate_iife: true,
@@ -242,7 +248,7 @@ issue_1254_negate_iife_nested: {
};
})()()()()();
}
expect_exact: '(function(){return function(){console.log("test")}})()()()()();'
expect_exact: 'function(){return function(){console.log("test")}}()()()()()'
expect_stdout: true
}

View File

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

View File

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

View File

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

View File

@@ -111,6 +111,7 @@ labels_5: {
labels_6: {
options = {
dead_code: true,
unused: true,
}
input: {
out: break out;
@@ -208,6 +209,59 @@ labels_10: {
expect_stdout: "PASS"
}
labels_11: {
options = {
conditionals: true,
if_return: true,
unused: true,
}
input: {
L: if (console.log("PASS"))
break L;
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
labels_12: {
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
L: try {
if (console.log("foo"))
break L;
throw "bar";
} catch (e) {
console.log(e);
break L;
} finally {
if (console.log("baz"))
break L;
}
}
expect: {
L: try {
if (!console.log("foo"))
throw "bar";
} catch (e) {
console.log(e);
} finally {
if (console.log("baz"))
break L;
}
}
expect_stdout: [
"foo",
"bar",
"baz",
]
}
issue_4466_1: {
mangle = {
v8: false,
@@ -327,3 +381,53 @@ issue_4466_2_toplevel_v8: {
}
expect_stdout: "PASS"
}
issue_5522: {
options = {
dead_code: true,
}
input: {
console.log(function() {
L: try {
return "FAIL";
} finally {
break L;
}
return "PASS";
}());
}
expect: {
console.log(function() {
L: try {
return "FAIL";
} finally {
break L;
}
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_5524: {
options = {
dead_code: true,
}
input: {
L: try {
FAIL;
} finally {
break L;
}
console.log("PASS");
}
expect: {
L: try {
FAIL;
} finally {
break L;
}
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -190,6 +190,96 @@ if_dead_branch: {
node_version: ">=4"
}
retain_tail_1: {
options = {
conditionals: true,
}
input: {
"use strict";
function f(a) {
var b = "foo";
if (a) {
let b = "bar";
while (console.log("baz"));
console.log(b);
} else {
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect: {
"use strict";
function f(a) {
var b = "foo";
if (a) {
let b = "bar";
while (console.log("baz"));
console.log(b);
} else {
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect_stdout: [
"moo",
"foo",
"baz",
"bar",
]
node_version: ">=4"
}
retain_tail_2: {
options = {
conditionals: true,
}
input: {
"use strict";
function f(a) {
var b = "foo";
if (a) {
while (console.log("bar"));
console.log(b);
} else {
let b = "baz";
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect: {
"use strict";
function f(a) {
var b = "foo";
if (a) {
while (console.log("bar"));
console.log(b);
} else {
let b = "baz";
while (console.log("moo"));
console.log(b);
}
}
f();
f(42);
}
expect_stdout: [
"moo",
"baz",
"bar",
"foo",
]
node_version: ">=4"
}
merge_vars_1: {
options = {
merge_vars: true,
@@ -892,6 +982,40 @@ if_return_2: {
node_version: ">=4"
}
if_return_3: {
options = {
if_return: true,
}
input: {
"use strict";
var a = "PASS";
function f(b) {
if (console) {
let b = a;
return b;
} else
while (console.log("FAIL 1"));
return b;
}
console.log(f("FAIL 2"));
}
expect: {
"use strict";
var a = "PASS";
function f(b) {
if (console) {
let b = a;
return b;
} else
while (console.log("FAIL 1"));
return b;
}
console.log(f("FAIL 2"));
}
expect_stdout: "PASS"
node_version: ">=4"
}
do_if_continue_1: {
options = {
if_return: true,
@@ -1604,48 +1728,6 @@ issue_4305_2: {
node_version: ">=4"
}
issue_1753: {
mangle = {
toplevel: false,
webkit: true,
}
input: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect_stdout: "0"
node_version: ">=4"
}
issue_1753_toplevel: {
mangle = {
toplevel: true,
webkit: true,
}
input: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect: {
"use strict";
let l = null;
for (let e = 0; e < 1; e++)
console.log(e);
}
expect_stdout: "0"
node_version: ">=4"
}
issue_4438: {
options = {
if_return: true,
@@ -1667,7 +1749,7 @@ issue_4438: {
function f() {
if (console) {
let a = console.log;
void a("PASS");
a("PASS");
}
}
f();
@@ -2020,3 +2102,71 @@ issue_5338: {
expect_stdout: ReferenceError("a is not defined")
node_version: ">=4"
}
issue_5476: {
mangle = {
keep_fargs: true,
}
input: {
"use strict";
console.log(function(n) {
let a;
}());
}
expect: {
"use strict";
console.log(function(n) {
let o;
}());
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_5591: {
options = {
dead_code: true,
if_return: true,
}
input: {
"use strict";
function f(a) {
switch (console.log("foo")) {
case console.log("bar"):
if (console.log("baz"))
return;
else {
let a;
return;
}
break;
case null:
FAIL;
}
}
f();
}
expect: {
"use strict";
function f(a) {
switch (console.log("foo")) {
case console.log("bar"):
if (console.log("baz"))
return;
else {
let a;
return;
}
case null:
FAIL;
}
}
f();
}
expect_stdout: [
"foo",
"bar",
"baz",
]
node_version: ">=4"
}

View File

@@ -3732,3 +3732,116 @@ issue_5420: {
}
expect_stdout: "PASS"
}
issue_5451: {
options = {
merge_vars: true,
toplevel: true,
}
input: {
A = 1;
var a = 1, b;
console.log(function f() {
return a-- && f(b = A, b);
}());
}
expect: {
A = 1;
var a = 1, b;
console.log(function f() {
return a-- && f(b = A, b);
}());
}
expect_stdout: "0"
}
issue_5471_1: {
options = {
conditionals: true,
inline: true,
merge_vars: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL 1";
function f(b, c) {
function g() {
if (console)
return 42;
else
c = "FAIL 2";
}
var d = g();
console.log(c || "PASS");
var e = function h() {
while (b && e);
}();
}
f(a++) && a;
}
expect: {
var a = "FAIL 1";
var b, c, e;
b = +a,
function() {
if (console)
return;
c = "FAIL 2";
}(),
console.log(c || "PASS"),
e = function() {
while (b && e);
}();
}
expect_stdout: "PASS"
}
issue_5471_2: {
options = {
conditionals: true,
evaluate: true,
inline: true,
merge_vars: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL 1";
function f(b, c) {
function g() {
if (console)
return 42;
else
c = "FAIL 2";
}
var d = g();
console.log(c || "PASS");
var e = function h() {
while (b && e);
}();
}
f(a++) && a;
}
expect: {
var a = "FAIL 1";
var b, c, e;
b = +a,
function() {
if (console)
return;
c = "FAIL 2";
}(),
console.log(c || "PASS"),
e = function() {
while (b && e);
}(),
void 0;
}
expect_stdout: "PASS"
}

View File

@@ -308,6 +308,7 @@ issue_4679: {
issue_5266: {
options = {
inline: true,
side_effects: true,
}
input: {
[

View File

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

View File

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

View File

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

View File

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

View File

@@ -2488,7 +2488,7 @@ side_effects_assign: {
console.log(a);
}
expect: {
var a = typeof void (a && a.in);
var a = "undefined";
console.log(a);
}
expect_stdout: "undefined"
@@ -2530,7 +2530,8 @@ pure_getters_2: {
var a = a && a.b;
}
expect: {
var a = a && a.b;
var a;
a && a.b;
}
}
@@ -5424,7 +5425,7 @@ issue_2774: {
get a() {
var b;
(b = true) && b.c;
b = void 0;
void 0;
}
}.a);
}
@@ -7896,3 +7897,33 @@ issue_5434: {
}
expect_stdout: "PASS"
}
issue_5623: {
options = {
collapse_vars: true,
evaluate: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = 0;
function f() {
var b = a;
a = b;
}
f && f((a++ && a).toString());
console.log(a);
}
expect: {
var a = 0;
function f() {
var b;
a = a;
}
f((a++ && a).toString());
console.log(a);
}
expect_stdout: "1"
}

View File

@@ -50,6 +50,22 @@ regexp_properties: {
expect_stdout: "abc true false 0 false"
}
instanceof_1: {
input: {
console.log(/foo/ instanceof RegExp);
}
expect_exact: "console.log(/foo/ instanceof RegExp);"
expect_stdout: "true"
}
instanceof_2: {
input: {
console.log(42 + /foo/ instanceof Object);
}
expect_exact: "console.log(42+/foo/ instanceof Object);"
expect_stdout: "false"
}
issue_3434_1: {
options = {
evaluate: true,

View File

@@ -648,7 +648,7 @@ drop_new_function: {
}
expect: {
void ([ ... {
[console.log("PASS")]: [].e,
[console.log("PASS")]: [][0],
}] = []);
}
expect_stdout: "PASS"
@@ -1363,3 +1363,264 @@ issue_5391: {
expect_stdout: "NaN"
node_version: ">=8.3.0"
}
issue_5533_1_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(...b) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_1_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(...b) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_2_keep_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(...[ b ]) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5533_2_drop_fargs: {
options = {
evaluate: true,
inline: true,
join_vars: true,
keep_fargs: false,
loops: true,
side_effects: true,
unused: true,
}
input: {
"use strict";
try {
(function() {
var a;
for (; 1;)
a = function() {
(function f(...[ b ]) {
b;
throw "PASS";
})();
}();
})();
} catch (e) {
console.log(e);
}
}
expect: {
"use strict";
try {
(function() {
for (;;)
throw "PASS";
})();
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5552_1: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var a = f, b = log();
function f(...[ c = a = "PASS" ]) {}
f((a = "FAIL", b));
log(a);
}
expect: {
var log = console.log;
var a = f, b = log();
function f(...[ c = a = "PASS" ]) {}
f((a = "FAIL", b));
log(a);
}
expect_stdout: [
"",
"PASS",
]
node_version: ">=6"
}
issue_5552_2: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
}
input: {
var log = console.log;
var a = f;
function f(...{ [a = "PASS"]: b }) {}
f((a = "FAIL", 42));
log(a);
}
expect: {
var log = console.log;
var a = f;
function f(...{ [a = "PASS"]: b }) {}
f((a = "FAIL", 42));
log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5552_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = [ "FAIL", "PASS" ];
console.log(function(b, ...[ c = a.pop() ]) {
return b;
}(a.pop()));
}
expect: {
var a = [ "FAIL", "PASS" ];
console.log(function(b, ...[ c = a.pop() ]) {
return b;
}(a.pop()));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_5552_4: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a = [ "FAIL", "PASS" ];
console.log(function(b, ...{ [a.pop()]: c }) {
return b;
}(a.pop()));
}
expect: {
var a = [ "FAIL", "PASS" ];
console.log(function(b, ...{ [a.pop()]: c }) {
return b;
}(a.pop()));
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -318,6 +318,32 @@ unsafe_string_replace: {
expect_stdout: "PASS"
}
unsafe_Object_call: {
options = {
side_effects: true,
unsafe: true,
}
input: {
var o = {
f: function(a) {
console.log(a ? this.p : "FAIL 1");
},
p: "FAIL 2",
}, p = "PASS";
Object(o.f)(42);
}
expect: {
var o = {
f: function(a) {
console.log(a ? this.p : "FAIL 1");
},
p: "FAIL 2",
}, p = "PASS";
(0, o.f)(42);
}
expect_stdout: "PASS"
}
drop_value: {
options = {
side_effects: true,
@@ -645,3 +671,56 @@ issue_4751: {
}
expect_stdout: "PASS"
}
drop_instanceof: {
options = {
side_effects: true,
}
input: {
42 instanceof function() {};
console.log("PASS");
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
drop_instanceof_reference: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
function f() {}
42 instanceof f;
console.log("PASS");
}
expect: {
function f() {}
console.log("PASS");
}
expect_stdout: "PASS"
}
retain_instanceof: {
options = {
side_effects: true,
}
input: {
try {
42 instanceof "foo";
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
0 instanceof "foo";
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}

View File

@@ -1,15 +1,24 @@
decimal: {
input: {
console.log({... 0.42});
}
expect_exact: "console.log({....42});"
expect_stdout: "{}"
node_version: ">=8.3.0"
}
collapse_vars_1: {
options = {
collapse_vars: true,
}
input: {
var a;
[ ...a = "PASS", "PASS"].slice();
[ ...a = "PASS", "PASS" ].slice();
console.log(a);
}
expect: {
var a;
[ ...a = "PASS", "PASS"].slice();
[ ...a = "PASS", "PASS" ].slice();
console.log(a);
}
expect_stdout: "PASS"
@@ -24,7 +33,7 @@ collapse_vars_2: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
[ ...42, "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -33,7 +42,7 @@ collapse_vars_2: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
[ ...42, "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -49,7 +58,7 @@ collapse_vars_3: {
input: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
[ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -57,7 +66,7 @@ collapse_vars_3: {
expect: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
[ ...(a = "PASS", 42), "PASS" ].slice();
} catch (e) {
console.log(a);
}
@@ -1194,3 +1203,53 @@ issue_5382: {
expect_stdout: "PASS"
node_version: ">=8.3.0"
}
issue_5602: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
if_return: true,
inline: true,
passes: 2,
sequences: true,
spreads: true,
unused: true,
}
input: {
(function() {
try {
var b = function(c) {
if (c)
return FAIL;
var d = 42;
}(...[ null, A = 0 ]);
} catch (e) {
b();
}
})();
console.log(A);
}
expect: {
(function() {
try {
var b = void (A = 0);
} catch (e) {
b();
}
})(),
console.log(A);
}
expect_stdout: "0"
expect_warnings: [
"INFO: Dropping unused variable d [test/compress/spreads.js:6,24]",
"INFO: Collapsing c [test/compress/spreads.js:4,24]",
"INFO: Dropping unused variable c [test/compress/spreads.js:3,33]",
"INFO: pass 0: last_count: Infinity, count: 27",
"WARN: Condition always false [test/compress/spreads.js:4,20]",
"INFO: Collapsing null [test/compress/spreads.js:7,23]",
"INFO: Collapsing 0 [test/compress/spreads.js:3,24]",
"INFO: pass 1: last_count: 27, count: 22",
]
node_version: ">=6"
}

View File

@@ -1608,3 +1608,83 @@ issue_5012: {
}
expect_stdout: "PASS"
}
issue_5543_1: {
options = {
dead_code: true,
switches: true,
}
input: {
var a;
switch (a) {
default:
switch (42) {
case a:
case console.log("PASS"):
}
break;
case null:
switch (false) {
case a:
case console.log("FAIL"):
}
}
}
expect: {
var a;
switch (a) {
default:
switch (42) {
case a:
case console.log("PASS"):
}
break;
case null:
switch (false) {
case a:
case console.log("FAIL"):
}
}
}
expect_stdout: "PASS"
}
issue_5543_2: {
options = {
dead_code: true,
switches: true,
}
input: {
var a;
switch (a) {
default:
switch (42) {
case a:
case console.log("PASS"):
}
break;
case null:
switch (42) {
case a:
case console.log("FAIL"):
}
}
}
expect: {
var a;
switch (a) {
default:
switch (42) {
case a:
case console.log("PASS"):
}
break;
case null:
switch (42) {
case a:
case console.log("FAIL"):
}
}
}
expect_stdout: "PASS"
}

View File

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

View File

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

View File

@@ -107,3 +107,209 @@ function_name_mangle_ie8: {
expect_exact: "(function(){console.log(typeof function n(o){})})();"
expect_stdout: "function"
}
issue_1753: {
mangle = {
toplevel: false,
webkit: true,
}
input: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect_stdout: "0"
node_version: ">=4"
}
issue_1753_toplevel: {
mangle = {
toplevel: true,
webkit: true,
}
input: {
"use strict";
let l = null;
for (let i = 0; i < 1; i++)
console.log(i);
}
expect: {
"use strict";
let l = null;
for (let e = 0; e < 1; e++)
console.log(e);
}
expect_stdout: "0"
node_version: ">=4"
}
issue_5032_await: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var a = log(a), c = a;
log(a);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5032_await_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect: {
function log(value) {
console.log(value);
return value;
}
async function f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=8"
}
issue_5032_yield: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var a = log(a), c = a;
log(a);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5032_yield_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5480: {
mangle = {
webkit: true,
}
input: {
"use strict";
L: for (let a in console.log("PASS"));
}
expect: {
"use strict";
o: for (let o in console.log("PASS"));
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -907,7 +907,7 @@ drop_body: {
})([ console.log("baz") ]);
}
expect: {
[ [ , [].e = console.log("foo") ] ] = [ [ console.log("baz") ] ];
[ [ , [][0] = console.log("foo") ] ] = [ [ console.log("baz") ] ];
}
expect_stdout: [
"baz",
@@ -934,6 +934,21 @@ drop_unused_call: {
node_version: ">=4"
}
instanceof_lambda: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(42 instanceof function*() {});
}
expect: {
console.log(false);
}
expect_stdout: "false"
node_version: ">=4"
}
issue_4454_1: {
rename = false
options = {
@@ -978,8 +993,8 @@ issue_4454_2: {
expect: {
function f(a) {
(function*(c = console.log(a)) {})();
var a = 42..toString();
console.log(a);
var b = 42..toString();
console.log(b);
}
f("PASS");
}
@@ -1168,6 +1183,35 @@ issue_4641_2: {
node_version: ">=10"
}
issue_4641_3: {
options = {
if_return: true,
}
input: {
console.log(typeof async function*() {
try {
return void "FAIL";
} finally {
console.log("PASS");
}
}().next().then);
}
expect: {
console.log(typeof async function*() {
try {
return void "FAIL";
} finally {
console.log("PASS");
}
}().next().then);
}
expect_stdout: [
"function",
"PASS",
]
node_version: ">=10"
}
issue_4769_1: {
options = {
side_effects: true,
@@ -1267,80 +1311,6 @@ issue_5019_2: {
node_version: ">=4"
}
issue_5032_normal: {
options = {
merge_vars: true,
webkit: false,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var a = log(a), c = a;
log(a);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5032_webkit: {
options = {
merge_vars: true,
webkit: true,
}
input: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect: {
function log(value) {
console.log(value);
return value;
}
function *f(a) {
var b = log(a), c = b;
log(b);
log(c);
}
f("PASS").next();
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
node_version: ">=4"
}
issue_5034: {
options = {
functions: true,
@@ -1526,6 +1496,80 @@ issue_5385_2: {
node_version: ">=10"
}
issue_5385_3: {
options = {
inline: true,
}
input: {
(async function*() {
return function() {
try {
throw console.log("foo");
} catch (e) {
return console.log("bar");
}
}();
})().next();
console.log("moo");
}
expect: {
(async function*() {
try {
throw console.log("foo");
} catch (e) {
return console.log("bar");
}
return void 0;
})().next();
console.log("moo");
}
expect_stdout: [
"foo",
"bar",
"moo",
]
node_version: ">=10"
}
issue_5385_4: {
options = {
awaits: true,
inline: true,
}
input: {
(async function*() {
return async function() {
try {
return {
then(resolve) {
resolve(console.log("FAIL"));
},
};
} finally {
return "PASS";
}
}();
})().next().then(o => console.log(o.value, o.done));
}
expect: {
(async function*() {
return async function() {
try {
return {
then(resolve) {
resolve(console.log("FAIL"));
},
};
} finally {
return "PASS";
}
}();
})().next().then(o => console.log(o.value, o.done));
}
expect_stdout: "PASS true"
node_version: ">=10"
}
issue_5425: {
options = {
assignments: true,
@@ -1547,3 +1591,430 @@ issue_5425: {
expect_stdout: "PASS undefined"
node_version: ">=4"
}
issue_5456: {
options = {
inline: true,
merge_vars: true,
}
input: {
var a = true;
(function() {
(function(b, c) {
var d = function*() {
c = null;
}();
var e = function() {
if (c)
console.log(typeof d);
while (b);
}();
})(function(i) {
return console.log("foo") && i;
}(a));
})();
}
expect: {
var a = true;
(function() {
b = (i = a, console.log("foo") && i),
d = function*() {
c = null;
}(),
e = function() {
if (c) console.log(typeof d);
while (b);
}(),
void 0;
var b, c, d, e;
var i;
})();
}
expect_stdout: "foo"
node_version: ">=4"
}
issue_5506: {
options = {
dead_code: true,
}
input: {
console.log(function(a) {
var b = function*() {
a = null in (a = "PASS");
}();
try {
b.next();
} catch (e) {
return a;
}
}("FAIL"));
}
expect: {
console.log(function(a) {
var b = function*() {
a = null in (a = "PASS");
}();
try {
b.next();
} catch (e) {
return a;
}
}("FAIL"));
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_5526: {
options = {
inline: true,
side_effects: true,
}
input: {
(async function*() {
try {
return function() {
while (console.log("foo"));
}();
} finally {
console.log("bar");
}
})().next();
console.log("baz");
}
expect: {
(async function*() {
try {
while (console.log("foo"));
return void 0;
} finally {
console.log("bar");
}
})().next();
console.log("baz");
}
expect_stdout: [
"foo",
"baz",
"bar",
]
node_version: ">=10"
}
issue_5576: {
options = {
inline: true,
}
input: {
(async function*() {
try {
(function() {
while (console.log("foo"));
})();
} finally {
console.log("bar");
}
})().next();
console.log("baz");
}
expect: {
(async function*() {
try {
while (console.log("foo"));
} finally {
console.log("bar");
}
})().next();
console.log("baz");
}
expect_stdout: [
"foo",
"bar",
"baz",
]
node_version: ">=10"
}
issue_5663: {
options = {
toplevel: true,
unused: true,
}
input: {
var [ , a ] = function*() {
console.log("foo");
yield console.log("bar");
console.log("baz");
yield console.log("moo");
console.log("moz");
yield FAIL;
}();
}
expect: {
var [ , , ] = function*() {
console.log("foo");
yield console.log("bar");
console.log("baz");
yield console.log("moo");
console.log("moz");
yield FAIL;
}();
}
expect_stdout: [
"foo",
"bar",
"baz",
"moo",
]
node_version: ">=6"
}
issue_5679_1: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
b;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_2: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return undefined;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return void 0;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_3: {
options = {
conditionals: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
else
return undefined;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return;
return void 0;
} finally {
a = "PASS";
}
}
f(42).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_4: {
options = {
conditionals: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return undefined;
else
return undefined;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
return b, void 0;
} finally {
a = "FAIL";
}
}
f(null).next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_5: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
else
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect: {
var a = "FAIL";
async function* f(b) {
try {
if (b)
return console;
return;
} finally {
a = "PASS";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5679_6: {
options = {
conditionals: true,
if_return: true,
}
input: {
var a = "PASS";
async function* f(b) {
try {
if (b)
return;
else
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect: {
var a = "PASS";
async function* f(b) {
try {
if (!b)
return console;
} finally {
a = "FAIL";
}
}
f().next();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=10"
}
issue_5684: {
options = {
conditionals: true,
if_return: true,
}
input: {
(async function*() {
switch (42) {
default:
if (console.log("PASS"))
return;
return null;
case false:
}
})().next();
}
expect: {
(async function*() {
switch (42) {
default:
return console.log("PASS") ? void 0 : null;
case false:
}
})().next();
}
expect_stdout: "PASS"
node_version: ">=10"
}

View File

@@ -38,4 +38,4 @@ var _require = require("bar"), foo = _require.foo;
var _require2 = require("world"), hello = _require2.hello;
foo.x.apply(foo, _toConsumableArray(foo.y(hello.z)));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHtmb299ID0gcmVxdWlyZShcImJhclwiKTtcbmNvbnN0IHtoZWxsb30gPSByZXF1aXJlKFwid29ybGRcIik7XG5cbmZvby54KC4uLmZvby55KGhlbGxvLnopKTtcbiJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiZm9vIiwiaGVsbG8iLCJ4IiwiYXBwbHkiLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJ5IiwieiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7ZUFBY0EsUUFBUSxRQUFmQyxNLFNBQUFBOztBLGdCQUNTRCxRQUFRLFVBQWpCRSxRLFVBQUFBOztBQUVQRCxJQUFJRSxFQUFKQyxNQUFBSCxLQUFHSSxtQkFBTUosSUFBSUssRUFBRUosTUFBTUsifQ==
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHtmb299ID0gcmVxdWlyZShcImJhclwiKTtcbmNvbnN0IHtoZWxsb30gPSByZXF1aXJlKFwid29ybGRcIik7XG5cbmZvby54KC4uLmZvby55KGhlbGxvLnopKTtcbiJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiZm9vIiwiaGVsbG8iLCJ4IiwiYXBwbHkiLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJ5IiwieiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7ZUFBY0EsUUFBUSxLQUFELEdBQWRDLE0sU0FBQUE7O0EsZ0JBQ1NELFFBQVEsT0FBRCxHQUFoQkUsUSxVQUFBQTs7QUFFUEQsSUFBSUUsRUFBSkMsTUFBQUgsS0FBR0ksbUJBQU1KLElBQUlLLEVBQUVKLE1BQU1LLENBQVosQ0FBTixDQUFBIn0=

View File

@@ -1,2 +1,2 @@
console.log(3);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSJ9
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSxDQUFHIn0=

View File

@@ -2,4 +2,4 @@ function test(a){
"aaaaaaaaaaaaaaaa";
a(err,data),a(err,
data)}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0E7SEFBS0M7QUFFVkE7aEJBQVNDLElBQUtDLE1BQ2RGLEVBQVNDLElBQUtDIn0=
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0E7SEFBS0MsR0FDVjtBQUNBQTtoQkFBU0MsSUFBS0MsSUFBSSxFQUNsQkYsRUFBU0MsSUFBS0MsSUFBSSxDQUN0QiJ9

View File

@@ -1,2 +1,2 @@
console.log(3);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSJ9
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSxDQUFHIn0=

View File

@@ -0,0 +1 @@
function n(){return this||arguments[0]+arguments[1]}function o(){return this||arguments[0]+arguments[1]}console.log(n(n(1,3),5)),console.log(o(o(2,4),6));

View File

@@ -0,0 +1,13 @@
console.log(function() {
function sum(...params) {
return this || arguments[0] + arguments[1];
}
return sum(sum(1, 3), 5);
}());
console.log(function() {
"use strict";
function sum(...params) {
return this || arguments[0] + arguments[1];
}
return sum(sum(2, 4), 6);
}());

View File

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

View File

@@ -1,13 +1,14 @@
var fs = require("fs");
var config = {
limit: 10000,
timeout: function(limit) {
this.limit = limit;
}
this.limit = limit + lag;
},
};
var lag = +process.env["UGLIFY_GITHUB_LAG"] || 0;
var tasks = [];
var titles = [];
config.timeout(10000);
describe = function(title, fn) {
config = Object.create(config);
titles.push(title);
@@ -21,10 +22,11 @@ it = function(title, fn) {
fn.titles.push(title);
tasks.push(fn);
};
fs.readdirSync("test/mocha").filter(function(file) {
(function(arg) {
return arg ? [ arg ] : fs.readdirSync("test/mocha").filter(function(file) {
return /\.js$/.test(file);
}).forEach(function(file) {
});
})(process.argv[2]).forEach(function(file) {
require("./mocha/" + file);
});
@@ -66,12 +68,13 @@ process.nextTick(function run() {
if (task.length) {
task.timeout = function(limit) {
clearTimeout(timer);
limit += lag;
task.limit = limit;
timer = setTimeout(function() {
raise(new Error("Timed out: exceeds " + limit + "ms"));
}, limit);
};
task.timeout(task.limit);
task.timeout(task.limit - lag);
process.on("uncaughtException", raise);
task.call(task, done);
} else {

View File

@@ -53,6 +53,23 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should work with --expression", function(done) {
exec([
uglifyjscmd,
"--expression",
"--compress",
"--mangle",
].join(" "), function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function(n){for(;n(););return 42}(A)\n");
done();
}).stdin.end([
"function(x) {",
" while (x()) {}",
" return 42;",
"}(A)",
].join("\n"));
});
it("Should work with --source-map names=true", function(done) {
exec([
uglifyjscmd,
@@ -69,7 +86,7 @@ describe("bin/uglifyjs", function() {
" q: b",
"};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
].join("\n")
].join("\n");
assert.strictEqual(stdout.slice(0, expected.length), expected);
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
@@ -97,7 +114,7 @@ describe("bin/uglifyjs", function() {
" q: b",
"};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,",
].join("\n")
].join("\n");
assert.strictEqual(stdout.slice(0, expected.length), expected);
var map = JSON.parse(to_ascii(stdout.slice(expected.length).trim()));
assert.deepEqual(map.names, []);
@@ -126,7 +143,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxHQUNYLENBRUEsT0FBT0MsR0FDVixFQUFFIn0=",
"",
].join("\n"));
done();
@@ -313,7 +330,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxHQUNYLENBRUEsT0FBT0MsR0FDVixFQUFFIn0=",
"",
].join("\n"));
var stderrLines = stderr.split("\n");
@@ -333,7 +350,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxJQUFPLElBQUlGLElDQW5ELElBQUlHLElBQU0sV0FDTixTQUFTQyxJQUFLRCxLQUNWLE9BQU9BLElBR1gsT0FBT0MsSUFMRCJ9",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxDQUFDLENBQUUsRUFBSSxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxHQUNYLENBRUEsT0FBT0MsR0FDVixFQUFFIn0=",
"",
].join("\n"));
var stderrLines = stderr.split("\n");
@@ -774,7 +791,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
'"use strict";var foo=function foo(x){return"foo "+x};console.log(foo("bar"));',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiYUFBQSxJQUFJQSxJQUFNLFNBQU5BLElBQU1DLEdBQUEsTUFBSyxPQUFTQSxHQUN4QkMsUUFBUUMsSUFBSUgsSUFBSSJ9",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiYUFBQSxJQUFJQSxJQUFNLFNBQU5BLElBQU1DLEdBQUEsTUFBSyxPQUFTQSxDQUFkLEVBQ1ZDLFFBQVFDLElBQUlILElBQUksS0FBSixDQUFaIn0=",
""
].join("\n"));
done();
@@ -797,7 +814,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
'function foo(){return function(){console.log("PASS")}}foo()();',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxNQUNMLE9BQU8sV0FDSEMsUUFBUUMsSUFBSSxNQUFNLENBQ3RCLENBQ0osQ0FHWUYsSUFBSSxFQUNWIn0=",
""
].join("\n"));
done();
@@ -928,6 +945,14 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should work with --module", function(done) {
var command = uglifyjscmd + " test/input/module/input.js --module -mc";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/module/expect.js"));
done();
});
});
it("Should compress swarm of unused variables with reasonable performance", function(done) {
var code = [
"console.log(function() {",

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
var acorn = require("acorn");
var assert = require("assert");
var UglifyJS = require("../node");
@@ -25,6 +26,7 @@ describe("export", function() {
"export { * };",
"export { * as A };",
"export { 42 as A };",
"export { 'A' as B };",
"export { A as B-C };",
"export { default as A };",
].forEach(function(code) {
@@ -51,8 +53,11 @@ describe("export", function() {
it("Should reject invalid `export ... from ...` statement syntax", function() {
[
"export from 'path';",
"export A from 'path';",
"export * from `path`;",
"export 'A' from 'path';",
"export A as B from 'path';",
"export 'A' as B from 'path';",
"export default from 'path';",
"export { A }, B from 'path';",
"export * as A, B from 'path';",
@@ -68,4 +73,109 @@ describe("export", function() {
}, code);
});
});
it("Should reject `export` statement not under top-level scope", function() {
[
"{ export {}; }",
"if (0) export var A;",
"function f() { export default 42; }",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
it("Should compare `export` statements correctly", function() {
var stats = {
Declaration: [
"export let A;",
"export const A = 42;",
"export var { A, B: [] } = C;",
"export function A() { return B(A); }",
"export async function* A({}, ...[]) { return B(A); }",
],
Default: [
"export default 42;",
"export default A => A(B);",
"export default class A extends B {}",
"export default (class A extends B {});",
"export default class A { static C = 42; }",
"export default class A extends B { static C = 42; }",
],
Foreign: [
"export * from 'path';",
"export {} from 'path';",
"export * as A from 'path';",
"export { default } from 'path';",
"export { A, B as C } from 'path';",
"export { A, default as C } from 'path';",
],
References: [
"export {};",
"export { A };",
"export { A as B };",
"export { A, B as C };",
"export { A as default };",
],
};
for (var k in stats) stats[k].forEach(function(c, i) {
var s = UglifyJS.parse(c);
assert.ok(s instanceof UglifyJS.AST_Toplevel, c);
assert.strictEqual(s.body.length, 1, c);
assert.strictEqual(s.body[0].TYPE, "Export" + k, c);
for (var l in stats) stats[l].forEach(function(d, j) {
var t = UglifyJS.parse(d);
assert.ok(t instanceof UglifyJS.AST_Toplevel, d);
assert.strictEqual(t.body.length, 1, d);
assert.strictEqual(t.body[0].TYPE, "Export" + l, d);
assert.strictEqual(s.equals(t), k === l && i === j, c + "\n" + d);
});
});
});
it("Should interoperate with ESTree correctly", function() {
[
"export var A = 42;",
"export default (class A {});",
"var A; export { A as '42' };",
"export { '42' } from 'path';",
"export * as '42' from 'path';",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
try {
var spidermonkey = ast.to_mozilla_ast();
} catch (ex) {
assert.fail("[to_mozilla_ast] " + ex.stack);
}
try {
var ast2 = UglifyJS.AST_Node.from_mozilla_ast(spidermonkey);
} catch (ex) {
assert.fail("[from_mozilla_ast] " + ex.stack);
}
assert.strictEqual(ast2.print_to_string(), ast.print_to_string(), [
"spidermonkey:",
ast.print_to_string(),
ast2.print_to_string(),
].join("\n"));
try {
var acorn_est = acorn.parse(code, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
});
} catch (ex) {
assert.fail("[acorn.parse] " + ex.stack);
}
try {
var ast3 = UglifyJS.AST_Node.from_mozilla_ast(acorn_est);
} catch (ex) {
assert.fail("[from_acorn] " + ex.stack);
}
assert.strictEqual(ast3.print_to_string(), ast.print_to_string(), [
"acorn:",
ast.print_to_string(),
ast3.print_to_string(),
].join("\n"));
});
});
});

View File

@@ -1,3 +1,4 @@
var acorn = require("acorn");
var assert = require("assert");
var UglifyJS = require("../node");
@@ -8,15 +9,25 @@ describe("import", function() {
"import A;",
"import {};",
"import `path`;",
"{ import 'path'; }",
"import from 'path';",
"if (0) import 'path';",
"import * from 'path';",
"import 'A' from 'path';",
"import A-B from 'path';",
"import A as B from 'path';",
"import { A }, B from 'path';",
"import * as 'A' from 'path';",
"import * as A-B from 'path';",
"import * as A, B from 'path';",
"import * as A, {} from 'path';",
"import { * as A } from 'path';",
"import { * as 'A' } from 'path';",
"import { * as A-B } from 'path';",
"function f() { import 'path'; }",
"import { 42 as A } from 'path';",
"import { A-B as C } from 'path';",
"import { 'A' as 'B' } from 'path';",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
@@ -25,4 +36,74 @@ describe("import", function() {
}, code);
});
});
it("Should compare `import` statements correctly", function() {
[
"import 'foo';",
"import 'path';",
"import A from 'path';",
"import { A } from 'path';",
"import * as A from 'path';",
"import A, { B } from 'path';",
"import A, * as B from 'path';",
"import { A as B } from 'path';",
"import A, { B, C as D } from 'path';",
].forEach(function(c, i, stats) {
var s = UglifyJS.parse(c);
assert.ok(s instanceof UglifyJS.AST_Toplevel, c);
assert.strictEqual(s.body.length, 1, c);
assert.ok(s.body[0] instanceof UglifyJS.AST_Import, c);
stats.forEach(function(d, j) {
var t = UglifyJS.parse(d);
assert.ok(t instanceof UglifyJS.AST_Toplevel, d);
assert.strictEqual(t.body.length, 1, d);
assert.ok(t.body[0] instanceof UglifyJS.AST_Import, d);
assert.strictEqual(s.equals(t), i === j, c + "\n" + d);
});
});
});
it("Should interoperate with ESTree correctly", function() {
[
"import A from 'path';",
"import * as A from 'path';",
"import A, * as B from 'path';",
"import { '42' as A, B } from 'path';",
"import A, { '42' as B } from 'path';",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
try {
var spidermonkey = ast.to_mozilla_ast();
} catch (ex) {
assert.fail("[to_mozilla_ast] " + ex.stack);
}
try {
var ast2 = UglifyJS.AST_Node.from_mozilla_ast(spidermonkey);
} catch (ex) {
assert.fail("[from_mozilla_ast] " + ex.stack);
}
assert.strictEqual(ast2.print_to_string(), ast.print_to_string(), [
"spidermonkey:",
ast.print_to_string(),
ast2.print_to_string(),
].join("\n"));
try {
var acorn_est = acorn.parse(code, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
});
} catch (ex) {
assert.fail("[acorn.parse] " + ex.stack);
}
try {
var ast3 = UglifyJS.AST_Node.from_mozilla_ast(acorn_est);
} catch (ex) {
assert.fail("[from_acorn] " + ex.stack);
}
assert.strictEqual(ast3.print_to_string(), ast.print_to_string(), [
"acorn:",
ast.print_to_string(),
ast3.print_to_string(),
].join("\n"));
});
});
});

View File

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

View File

@@ -1,6 +1,7 @@
var assert = require("assert");
var readFileSync = require("fs").readFileSync;
var run_code = require("../sandbox").run_code;
var semver = require("semver");
var UglifyJS = require("../..");
function read(path) {
@@ -109,10 +110,12 @@ describe("minify", function() {
var result = UglifyJS.minify(code, {
compress: false,
mangle: {
properties: true,
toplevel: true
properties: {
domprops: true,
},
nameCache: cache
toplevel: true,
},
nameCache: cache,
});
if (result.error) throw result.error;
original += code;
@@ -187,32 +190,30 @@ describe("minify", function() {
it("Shouldn't mangle quoted properties", function() {
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
var result = UglifyJS.minify(js, {
compress: {
properties: false
},
compress: true,
mangle: {
properties: {
keep_quoted: true
}
domprops: true,
keep_quoted: true,
},
},
output: {
keep_quoted_props: true,
quote_style: 3
}
quote_style: 3,
},
});
assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};');
assert.strictEqual(result.code, 'a["foo"]="bar",a.a="red",x={"bar":10};');
});
it("Should not mangle quoted property within dead code", function() {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change;', {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change = 42;', {
mangle: {
properties: {
keep_quoted: true
}
}
keep_quoted: true,
},
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g;");
assert.strictEqual(result.code, "g.keep=g.g=42;");
});
});
@@ -320,6 +321,24 @@ describe("minify", function() {
});
});
describe("module", function() {
it("Should not inline `await` variables", function() {
if (semver.satisfies(process.version, "<8")) return;
var code = [
"console.log(function() {",
" return typeof await;",
"}());",
].join("\n");
assert.strictEqual(run_code("(async function(){" + code + "})();"), "undefined\n");
var result = UglifyJS.minify(code, {
module: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "console.log(function(){return typeof await}());");
assert.strictEqual(run_code("(async function(){" + result.code + "})();"), "undefined\n");
});
});
describe("rename", function() {
it("Should be repeatable", function() {
var code = "!function(x){return x(x)}(y);";

View File

@@ -50,12 +50,10 @@ describe("Number literals", function() {
"0.000_000_004_2e+1_0-0B101_010+0x2_A-0o5_2+4_2",
].forEach(function(code) {
var result = UglifyJS.minify(code, {
compress: {
expression: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "42;");
assert.strictEqual(result.code, "42");
});
});
it("Should reject invalid use of underscore", function() {

View File

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

View File

@@ -19,11 +19,11 @@ function source_map(code) {
function get_map() {
return {
"version": 3,
"sources": ["index.js"],
"sources": [ "index.js" ],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
"sourcesContent": [ "let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));" ],
};
}
@@ -42,7 +42,7 @@ function prepare_map(sourceMap) {
sourceMap: {
content: sourceMap,
includeSources: true,
}
},
});
if (result.error) throw result.error;
return JSON.parse(result.map);
@@ -112,7 +112,7 @@ describe("sourcemaps", function() {
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "class A{static P=42;set#q(s){}}");
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["A","P","#q","v"],"mappings":"MAAMA,EACFC,SAAW,GACXC,MAAOC"}');
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["A","P","#q","v"],"mappings":"MAAMA,EACFC,SAAW,GACXC,MAAOC,IACX"}');
});
it("Should mark array/object literals", function() {
var result = UglifyJS.minify([
@@ -124,7 +124,7 @@ describe("sourcemaps", function() {
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "({}).wat([]);");
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["wat"],"mappings":"CAAU,IACNA,IAAI"}');
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["wat"],"mappings":"CAAU,IACNA,IAAI,EAAE"}');
});
it("Should give correct sourceRoot", function() {
var code = "console.log(42);";
@@ -135,7 +135,7 @@ describe("sourcemaps", function() {
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI"}');
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI,EAAE"}');
});
it("Should produce same source map with DOS or UNIX line endings", function() {
var code = [
@@ -160,8 +160,8 @@ describe("sourcemaps", function() {
sourceMap: {
content: read("test/input/issue-1236/simple.js.map"),
filename: "simple.min.js",
includeSources: true
}
includeSources: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
@@ -175,8 +175,8 @@ describe("sourcemaps", function() {
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
url: "inline",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
@@ -185,7 +185,7 @@ describe("sourcemaps", function() {
var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
mangle: false,
sourceMap: {
content: "inline"
content: "inline",
},
warnings: true,
});
@@ -206,7 +206,7 @@ describe("sourcemaps", function() {
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"var Foo=function(){console.log(3)},bar=(new Foo,function(o){return o});",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElDQWxDQyxLREEyQyxJQUFJSCxJQ0MvQyxTQUFjRyxHQUNWLE9BQU9BIn0=",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLENBQUcsQ0FBRSxFQ0F2Q0MsS0RBMkMsSUFBSUgsSUNDL0MsU0FBY0csR0FDVixPQUFPQSxDQUNYIn0=",
].join("\n"));
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
});
@@ -239,13 +239,13 @@ describe("sourcemaps", function() {
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
url: "inline",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
});
it("Should work in presence of unrecognised annotations", function() {
it("Should work in presence of unrecognized annotations", function() {
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false,
mangle: false,
@@ -255,7 +255,7 @@ describe("sourcemaps", function() {
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){console.log("hello")}).call(this);');
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI"}');
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI,OAAZ"}');
});
it("Should not overwrite existing sourcesContent", function() {
var result = UglifyJS.minify({
@@ -302,7 +302,7 @@ describe("sourcemaps", function() {
if (result.error) throw result.error;
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BLENBQUsifQ==");
});
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; };');

View File

@@ -9,19 +9,22 @@ function beautify(ast) {
var beautified = UglifyJS.minify(ast, {
compress: false,
mangle: false,
module: ufuzz.module,
output: {
ast: true,
beautify: true,
braces: true,
},
});
if (beautified.error) return beautified;
return UglifyJS.minify(beautified.code, {
if (!beautified.error) {
var verify = UglifyJS.minify(beautified.code, {
compress: false,
mangle: false,
output: {
ast: true,
},
module: ufuzz.module,
});
if (verify.error) return verify;
}
return beautified;
}
function validate(ast) {
@@ -35,6 +38,7 @@ function validate(ast) {
return UglifyJS.minify(ast, {
compress: false,
mangle: false,
module: ufuzz.module,
output: {
ast: true,
},
@@ -57,12 +61,12 @@ function test(input, to_moz, description, skip_on_error, beautified) {
var ast = UglifyJS.AST_Node.from_mozilla_ast(to_moz(input));
} catch (e) {
if (skip_on_error) return true;
console.log("//=============================================================");
console.log("//", description, "failed... round", round);
console.log(e);
console.log("// original code");
if (beautified === true) console.log("// (beautified)");
console.log(input.code);
console.error("//=============================================================");
console.error("//", description, "failed... round", round);
console.error(e);
console.error("// original code");
if (beautified === true) console.error("// (beautified)");
console.error(input.code);
return false;
}
var transformed = validate(ast);
@@ -74,34 +78,34 @@ function test(input, to_moz, description, skip_on_error, beautified) {
if (!test(beautified, to_moz, description, skip_on_error, true)) return false;
}
}
console.log("//=============================================================");
console.log("// !!!!!! Failed... round", round);
console.log("// original code");
console.error("//=============================================================");
console.error("// !!!!!! Failed... round", round);
console.error("// original code");
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.error("// !!! beautify failed !!!");
console.error(beautified.error.stack);
} else if (beautified === true) {
console.log("// (beautified)");
console.error("// (beautified)");
}
console.log(input.raw);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("//", description);
console.error(input.raw);
console.error();
console.error();
console.error("//-------------------------------------------------------------");
console.error("//", description);
if (transformed.error) {
console.log(transformed.error.stack);
console.error(transformed.error.stack);
} else {
beautified = beautify(transformed.ast);
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.log(transformed.code);
console.error("// !!! beautify failed !!!");
console.error(beautified.error.stack);
console.error(transformed.code);
} else {
console.log("// (beautified)");
console.log(beautified.code);
console.error("// (beautified)");
console.error(beautified.code);
}
}
console.log("!!!!!! Failed... round", round);
console.error("!!!!!! Failed... round", round);
return false;
}
return true;
@@ -115,9 +119,29 @@ for (var round = 1; round <= num_iterations; round++) {
var code = ufuzz.createTopLevelCode();
minify_options.forEach(function(options) {
var ok = true;
var input = UglifyJS.minify(options ? UglifyJS.minify(code, JSON.parse(options)).code : code, {
var minified;
if (options) {
var o = JSON.parse(options);
o.module = ufuzz.module;
minified = UglifyJS.minify(code, o);
if (minified.error) {
console.log("//=============================================================");
console.log("// minify() failed... round", round);
console.log("// original code");
console.log(code);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("minify(options):");
console.log(JSON.stringify(o, null, 2));
return;
}
minified = minified.code;
}
var input = UglifyJS.minify(minified || code, {
compress: false,
mangle: false,
module: ufuzz.module,
output: {
ast: true,
},
@@ -125,11 +149,27 @@ for (var round = 1; round <= num_iterations; round++) {
input.raw = options ? input.code : code;
if (input.error) {
ok = false;
console.log("//=============================================================");
console.log("// minify() failed... round", round);
console.log(input.error);
console.log("// original code");
console.log(code);
console.error("//=============================================================");
console.error("// parse() failed... round", round);
console.error("// original code");
console.error(code);
console.error();
console.error();
if (options) {
console.error("//-------------------------------------------------------------");
console.error("// minified code");
console.error(minified);
console.error();
console.error();
console.error("//-------------------------------------------------------------");
console.error("minify(options):");
console.error(JSON.stringify(o, null, 2));
console.error();
console.error();
}
console.error("//-------------------------------------------------------------");
console.error("// parse() error");
console.error(input.error);
}
if (ok) ok = test(input, function(input) {
return input.ast.to_mozilla_ast();
@@ -141,7 +181,10 @@ for (var round = 1; round <= num_iterations; round++) {
sourceType: "module",
});
}, "acorn.parse()", !ufuzz.verbose);
if (!ok) process.exit(1);
if (!ok && isFinite(num_iterations)) {
console.log();
process.exit(1);
}
});
}
console.log();

View File

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

View File

@@ -160,6 +160,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return expr instanceof U.AST_Spread ? expr.expression : expr;
}
}
else if (node instanceof U.AST_Await) {
node.start._permute++;
CHANGED = true;
return node.expression;
}
else if (node instanceof U.AST_Binary) {
var permute = ((node.start._permute += step) * steps | 0) % 4;
var expr = [
@@ -210,10 +215,10 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
if (node.expression instanceof U.AST_Function) {
// hoist and return expressions from the IIFE function expression
var seq = [];
var scope = tt.find_parent(U.AST_Scope), seq = [];
node.expression.body.forEach(function(node) {
var expr = node instanceof U.AST_Exit ? node.value : node.body;
if (expr instanceof U.AST_Node && !U.is_statement(expr) && can_hoist(expr)) {
if (expr instanceof U.AST_Node && !U.is_statement(expr) && can_hoist(expr, scope)) {
// collect expressions from each statement's body
seq.push(expr);
}
@@ -241,6 +246,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
CHANGED = true;
return node.name;
}
else if (node instanceof U.AST_Defun) {
switch (((node.start._permute += step) * steps | 0) % 2) {
case 0:
CHANGED = true;
return List.skip;
default:
if (can_hoist(node, tt.find_parent(U.AST_Scope))) {
// hoist function declaration body
var body = node.body;
node.body = [];
// retain function with empty body to be dropped later
body.push(node);
CHANGED = true;
return List.splice(body);
}
}
}
else if (node instanceof U.AST_DestructuredArray) {
var expr = node.elements[0];
if (expr && !(expr instanceof U.AST_Hole)) {
@@ -258,22 +280,6 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return expr.value;
}
}
else if (node instanceof U.AST_Defun) {
switch (((node.start._permute += step) * steps | 0) % 2) {
case 0:
CHANGED = true;
return List.skip;
default:
if (!has_exit(node) && can_hoist(node)) {
// hoist function declaration body
var body = node.body;
node.body = [];
body.push(node); // retain function with empty body to be dropped later
CHANGED = true;
return List.splice(body);
}
}
}
else if (node instanceof U.AST_DWLoop) {
var expr = [
node.condition,
@@ -295,6 +301,16 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return to_statement(expr);
}
}
else if (node instanceof U.AST_ExportDeclaration) {
node.start._permute++;
CHANGED = true;
return node.body;
}
else if (node instanceof U.AST_ExportDefault) {
node.start._permute++;
CHANGED = true;
return to_statement(node.body);
}
else if (node instanceof U.AST_Finally) {
// drop finally block
node.start._permute++;
@@ -350,6 +366,15 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return to_statement(expr);
}
}
else if (node instanceof U.AST_LabeledStatement) {
if (node.body instanceof U.AST_Statement
&& !has_loopcontrol(node.body, node.body, node)) {
// replace labelled statement with its non-labelled body
node.start._permute = REPLACEMENTS.length;
CHANGED = true;
return node.body;
}
}
else if (node instanceof U.AST_Object) {
// first property's value
var expr = node.properties[0];
@@ -382,7 +407,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
// hoist simple statement IIFE function expression body
node.start._permute++;
if (!has_exit(node.body.expression) && can_hoist(node.body.expression)) {
if (can_hoist(node.body.expression, tt.find_parent(U.AST_Scope))) {
CHANGED = true;
return List.splice(node.body.expression.body);
}
@@ -440,13 +465,14 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return to_statement(node.definitions[0].value);
}
}
else if (node instanceof U.AST_LabeledStatement) {
if (node.body instanceof U.AST_Statement
&& !has_loopcontrol(node.body, node.body, node)) {
// replace labelled statement with its non-labelled body
node.start._permute = REPLACEMENTS.length;
else if (node instanceof U.AST_VarDef) {
if (node.value && !(node.name instanceof U.AST_Destructured || parent instanceof U.AST_Const)) {
node.start._permute++;
CHANGED = true;
return node.body;
return new U.AST_VarDef({
name: node.name,
start: {},
});
}
}
@@ -647,21 +673,6 @@ function trim_trailing_whitespace(value) {
return ("" + value).replace(/\s+$/, "");
}
function has_exit(fn) {
var found = false;
var tw = new U.TreeWalker(function(node) {
if (found) return found;
if (node instanceof U.AST_Exit) {
return found = true;
}
if (node instanceof U.AST_Scope && node !== fn) {
return true; // don't descend into nested functions
}
});
fn.walk(tw);
return found;
}
function has_loopcontrol(body, loop, label) {
var found = false;
var tw = new U.TreeWalker(function(node) {
@@ -676,17 +687,31 @@ function has_loopcontrol(body, loop, label) {
return found;
}
function can_hoist(body) {
function can_hoist(body, scope) {
var found = false;
body.walk(new U.TreeWalker(function(node) {
var tw = new U.TreeWalker(function(node) {
if (found) return true;
if (node instanceof U.AST_Exit) return found = true;
if (node instanceof U.AST_NewTarget) return found = true;
if (node instanceof U.AST_Scope) {
if (node === body) return;
if (node instanceof U.AST_Arrow || node instanceof U.AST_AsyncArrow) node.argnames.forEach(function(sym) {
sym.walk(tw);
});
// don't descend into nested functions
return true;
}
if (node instanceof U.AST_Super) return found = true;
}));
if (node instanceof U.AST_SymbolDeclaration || node instanceof U.AST_SymbolRef) switch (node.name) {
case "await":
if (/^Async/.test(scope.TYPE)) return found = true;
return;
case "yield":
if (/Generator/.test(scope.TYPE)) return found = true;
return;
}
});
body.walk(tw);
return !found;
}
@@ -760,9 +785,9 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
if (minified.error) return minified;
var toplevel = sandbox.has_toplevel(minify_options);
var unminified = run_code(code, toplevel, result_cache, max_timeout);
var unminified = run(code, max_timeout);
var timeout = Math.min(100 * unminified.elapsed, max_timeout);
var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result;
var minified_result = run(minified.code, timeout).result;
if (sandbox.same_stdout(unminified.result, minified_result)) {
return is_timed_out(unminified.result) && is_timed_out(minified_result) && {
@@ -774,6 +799,16 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
minified_result: minified_result,
elapsed: unminified.elapsed,
};
function run(code, timeout) {
if (minify_options.module) code = [
'"use strict";',
"(async()=>{",
code,
'})().catch(e=>process.on("exit",()=>{throw e}));',
].join("\n");
return run_code(code, toplevel, result_cache, timeout);
}
}
function test_minify(code, minify_options) {

View File

@@ -36,7 +36,7 @@ EOF
}
if [ $NATIVE ]; then unset -f timeout; fi
while !(git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs); do
while !(git clone --branch v1.6.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs); do
rm -rf ~/.nvs
done
while ! timeout 60 bash -c ". ~/.nvs/nvs.sh add $NODE && nvs use $NODE"; do
@@ -48,6 +48,8 @@ done
nvs use $NODE
node --version
npm config set audit false
npm config set fund false
npm config set loglevel error
npm config set optional false
npm config set save false
npm config set strict-ssl false

View File

@@ -54,7 +54,7 @@ ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
minify_in_situ "src" \
&& minify_in_situ "third_party" \
&& rm -rf node_modules \
&& npm_install \
&& npm_install --package-lock \
&& rm -rf build/* \
&& npm run build:terser-bundled \
&& npm run build:uglify-js-bundled \

View File

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

View File

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

View File

@@ -140,6 +140,7 @@ var SUPPORT = function(matrix) {
class: "class C { f() {} }",
class_field: "class C { p = 0; }",
class_private: "class C { #f() {} }",
class_static_init: "class C { static {} }",
computed_key: "({[0]: 0});",
const_block: "var a; { const a = 0; }",
default_value: "[ a = 0 ] = [];",
@@ -252,7 +253,7 @@ BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
if (SUPPORT.exponentiation) BINARY_OPS.push("**");
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS.push(" in ");
BINARY_OPS.push(" in ", " instanceof ");
var ASSIGNMENTS = [ "=" ];
ASSIGNMENTS = ASSIGNMENTS.concat(ASSIGNMENTS);
@@ -370,9 +371,16 @@ var in_class = 0;
var called = Object.create(null);
var labels = 10000;
function rng(max) {
function rng(limit) {
var r = randomBytes(2).readUInt16LE(0) / 65536;
return Math.floor(max * r);
return Math.floor(limit * r);
}
function get_num(max) {
if (rng(max + 1) == 0) return 0;
var i = 1;
while (i < max && rng(2)) i++;
return i;
}
function strictMode() {
@@ -405,7 +413,7 @@ function createTopLevelCode() {
unique_vars.length = 0;
classes.length = 0;
allow_this = true;
async = false;
async = SUPPORT.async && rng(200) == 0;
has_await = false;
export_default = false;
generator = false;
@@ -413,7 +421,7 @@ function createTopLevelCode() {
funcs = 0;
clazz = 0;
imports = 0;
in_class = 0;
in_class = async;
called = Object.create(null);
var s = [
strictMode(),
@@ -424,7 +432,7 @@ function createTopLevelCode() {
if (rng(2)) {
s.push(createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0));
} else {
s.push(createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0));
s.push(createFunctions(MAX_GENERATED_TOPLEVELS_PER_RUN, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0));
}
});
// preceding `null` makes for a cleaner output (empty string still shows up etc)
@@ -437,7 +445,7 @@ function createTopLevelCode() {
function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
if (--recurmax < 0) { return ";"; }
var s = "";
while (n-- > 0) {
for (var i = get_num(n - 1) + 1; --i >= 0;) {
s += createFunction(recurmax, allowDefun, canThrow, stmtDepth) + "\n";
}
return s;
@@ -454,7 +462,7 @@ function createParams(was_async, was_generator, noDuplicate) {
if (!generator) generator = was_generator;
var len = unique_vars.length;
var params = [];
for (var n = rng(4); --n >= 0;) {
for (var i = get_num(3); --i >= 0;) {
var name = createVarName(MANDATORY);
if (noDuplicate || in_class) unique_vars.push(name);
params.push(name);
@@ -469,7 +477,7 @@ function createArgs(recurmax, stmtDepth, canThrow, noTemplate) {
recurmax--;
if (SUPPORT.template && !noTemplate && rng(20) == 0) return createTemplateLiteral(recurmax, stmtDepth, canThrow);
var args = [];
for (var n = rng(4); --n >= 0;) switch (SUPPORT.spread ? rng(50) : 3) {
for (var i = get_num(3); --i >= 0;) switch (SUPPORT.spread ? rng(50) : 3) {
case 0:
case 1:
var name = getVarName();
@@ -849,7 +857,7 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
s.push(defns());
if (rng(5) === 0) {
// functions with functions. lower the recursion to prevent a mess.
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
s.push(createFunctions(5, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
} else {
// functions with statements
s.push(_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
@@ -879,9 +887,9 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
}
function _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
if (--recurmax < 0) { return ";"; }
if (--recurmax < 0) return ";";
var s = "";
while (--n > 0) {
for (var i = get_num(n); --i >= 0;) {
s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "\n";
}
return s;
@@ -962,7 +970,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
switch (target) {
case STMT_BLOCK:
var label = createLabel(canBreak);
return label.target + "{" + createStatements(rng(5) + 1, recurmax, canThrow, label.break, canContinue, cannotReturn, stmtDepth) + "}";
return label.target + "{" + createStatements(5, recurmax, canThrow, label.break, canContinue, cannotReturn, stmtDepth) + "}";
case STMT_IF_ELSE:
return "if (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) ? " else " + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : "");
case STMT_DO_WHILE:
@@ -1075,7 +1083,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
s += " * as " + createImportAlias();
} else {
var names = [];
for (var i = rng(4); --i >= 0;) {
for (var i = get_num(3); --i >= 0;) {
var name = createImportAlias();
names.push(rng(2) ? getDotKey() + " as " + name : name);
}
@@ -1134,7 +1142,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
}
case STMT_FUNC_EXPR:
// "In non-strict mode code, functions can only be declared at top level, inside a block, or ..."
// (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block)
// (don't make func decls in `if`; it's only a parser thing because you can't call them without a block)
return "{" + createFunction(recurmax, NO_DEFUN, canThrow, stmtDepth) + "}";
case STMT_TRY:
// catch var could cause some problems
@@ -1181,7 +1189,11 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
unique_vars.length = unique_len;
});
}
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
if (n !== 0) s += [
" finally { ",
createStatements(5, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
" }",
].join("");
return s;
case STMT_C:
return "c = c + 1;";
@@ -1199,7 +1211,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
if (hadDefault || rng(5) > 0) {
s.push(
"case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":",
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
_createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
rng(10) > 0 ? " break;" : "/* fall-through */",
""
);
@@ -1207,7 +1219,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
hadDefault = true;
s.push(
"default:",
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
_createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
""
);
}
@@ -1338,7 +1350,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
"(" + params + "{",
strictMode(),
defns(),
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)
_createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)
);
suffix = "})";
} else {
@@ -1370,7 +1382,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
s.push(
"(" + makeFunction(name) + "(){",
strictMode(),
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
rng(2) ? "})" : "})()" + invokeGenerator(save_generator)
);
}
@@ -1379,7 +1391,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
s.push(
"+" + makeFunction(name) + "(){",
strictMode(),
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
"}()" + invokeGenerator(save_generator)
);
break;
@@ -1387,7 +1399,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
s.push(
"!" + makeFunction(name) + "(){",
strictMode(),
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
"}()" + invokeGenerator(save_generator)
);
break;
@@ -1395,7 +1407,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
s.push(
"void " + makeFunction(name) + "(){",
strictMode(),
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
"}()" + invokeGenerator(save_generator)
);
break;
@@ -1411,10 +1423,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
var add_new_target = SUPPORT.new_target && VALUES.indexOf("new.target") < 0;
if (add_new_target) VALUES.push("new.target");
s.push(defns());
if (instantiate) for (var i = rng(4); --i >= 0;) {
if (instantiate) for (var i = get_num(3); --i >= 0;) {
s.push((in_class ? "if (this) " : "") + createThisAssignment(recurmax, stmtDepth, canThrow));
}
s.push(_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
s.push(_createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
if (add_new_target) VALUES.splice(VALUES.indexOf("new.target"), 1);
});
generator = save_generator;
@@ -1560,7 +1572,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
recurmax--;
var arr = [];
for (var i = rng(6); --i >= 0;) switch (SUPPORT.spread ? rng(50) : 3 + rng(47)) {
for (var i = get_num(5); --i >= 0;) switch (SUPPORT.spread ? rng(50) : 3 + rng(47)) {
case 0:
case 1:
var name = getVarName();
@@ -1589,7 +1601,7 @@ function createTemplateLiteral(recurmax, stmtDepth, canThrow) {
recurmax--;
var s = [];
addText();
for (var i = rng(6); --i >= 0;) {
for (var i = get_num(5); --i >= 0;) {
s.push("${", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "}");
addText();
}
@@ -1744,7 +1756,7 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth));
if (internal == "super") s.push("super" + createArgs(recurmax, stmtDepth, canThrow, NO_TEMPLATE) + ";");
allow_this = save_allow;
if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = rng(4); --i >= 0;) {
if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = get_num(3); --i >= 0;) {
s.push(rng(2) ? createSuperAssignment(recurmax, stmtDepth, canThrow) : createThisAssignment(recurmax, stmtDepth, canThrow));
}
s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), "}");
@@ -1763,7 +1775,7 @@ function createObjectLiteral(recurmax, stmtDepth, canThrow) {
var obj = [ "({" ];
var offset = SUPPORT.spread_object ? 0 : SUPPORT.computed_key ? 2 : 4;
var has_proto = false;
for (var i = rng(6); --i >= 0;) switch (offset + rng(50 - offset)) {
for (var i = get_num(5); --i >= 0;) switch (offset + rng(50 - offset)) {
case 0:
obj.push("..." + getVarName() + ",");
break;
@@ -1805,12 +1817,12 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
if (canThrow && rng(20) == 0) {
s += p;
} else {
s += "(" + p + " && " + p + ".constructor === Function ? " + p + " : function() {})";
s += "(typeof " + p + ' == "function" && typeof ' + p + '.prototype == "object" && ' + p + ".constructor === Function ? " + p + " : function() {})";
}
}
s += " {\n";
var declared = [];
for (var i = rng(6); --i >= 0;) {
for (var i = get_num(5); --i >= 0;) {
var fixed = false;
if (rng(5) == 0) {
fixed = true;
@@ -1826,19 +1838,29 @@ function createClassLiteral(recurmax, stmtDepth, canThrow, name) {
if (SUPPORT.class_field && rng(2)) {
if (internal) {
s += internal;
} else if (fixed && bug_static_class_field) {
} else if (fixed && bug_class_static_nontrivial) {
s += getDotKey();
} else {
s += createObjectKey(recurmax, stmtDepth, canThrow);
}
if (rng(5)) {
async = bug_async_class_await && fixed && 0;
async = false;
generator = false;
s += " = " + createExpression(recurmax, NO_COMMA, stmtDepth, fixed ? canThrow : CANNOT_THROW);
generator = save_generator;
async = save_async;
}
s += ";\n";
} else if (SUPPORT.class_static_init && fixed && !internal && rng(10) == 0) {
async = false;
generator = false;
s += [
"{ ",
createStatements(5, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth),
" }\n",
].join("");
generator = save_generator;
async = save_async;
} else {
if (!fixed && !internal && constructor && rng(10) == 0) {
internal = constructor;
@@ -1994,7 +2016,7 @@ function createBinaryOp(noComma, canThrow) {
var op;
do {
op = BINARY_OPS[rng(BINARY_OPS.length)];
} while (noComma && op == "," || !canThrow && op == " in ");
} while (noComma && op == "," || !canThrow && /^ in/.test(op));
return op;
}
@@ -2037,7 +2059,7 @@ function isBannedKeyword(name) {
case "let":
return in_class;
case "await":
return async !== false;
return async || in_class && bug_class_static_await;
case "yield":
return generator || in_class;
}
@@ -2080,13 +2102,23 @@ function createVarName(maybe, dontStore) {
}
if (require.main !== module) {
exports.createTopLevelCode = createTopLevelCode;
exports.createTopLevelCode = function() {
var code = createTopLevelCode();
exports.module = async && has_await;
return code;
};
exports.num_iterations = num_iterations;
exports.verbose = verbose;
return;
}
function run_code(code, toplevel, timeout) {
if (async && has_await) code = [
'"use strict";',
"(async()=>{",
code,
'})().catch(e=>process.on("exit",()=>{throw e}));',
].join("\n");
return sandbox.run_code(sandbox.patch_module_statements(code), toplevel, timeout);
}
@@ -2106,7 +2138,9 @@ function errorln(msg) {
}
function try_beautify(code, toplevel, result, printfn, options) {
var beautified = UglifyJS.minify(code, JSON.parse(beautify_options));
var o = JSON.parse(beautify_options);
if (async && has_await) o.module = true;
var beautified = UglifyJS.minify(code, o);
if (beautified.error) {
printfn("// !!! beautify failed !!!");
printfn(beautified.error);
@@ -2259,12 +2293,27 @@ function log(options) {
}
function sort_globals(code) {
var globals = run_code("throw Object.keys(this).sort(" + function(global) {
var injected = "throw Object.keys(this).sort(" + function(global) {
return function(m, n) {
return (typeof global[n] == "function") - (typeof global[m] == "function")
|| (m < n ? -1 : m > n ? 1 : 0);
};
} + "(this));\n" + code);
} + "(this));";
var save_async = async;
if (async && has_await) {
async = false;
injected = [
'"use strict";',
injected,
"(async function(){",
code,
"})();"
].join("\n");
} else {
injected += "\n" + code;
}
var globals = run_code(injected);
async = save_async;
if (!Array.isArray(globals)) {
errorln();
errorln();
@@ -2324,20 +2373,28 @@ function is_error_in(ex) {
return ex.name == "TypeError" && /'in'/.test(ex.message);
}
function is_error_tdz(ex) {
return ex.name == "ReferenceError";
}
function is_error_spread(ex) {
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function/.test(ex.message);
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function|Symbol\(Symbol\.iterator\)/.test(ex.message);
}
function is_error_recursion(ex) {
return ex.name == "RangeError" && /Invalid string length|Maximum call stack size exceeded/.test(ex.message);
}
function is_error_set_property(ex) {
return ex.name == "TypeError" && /^Cannot set propert[\s\S]+? of (null|undefined)/.test(ex.message);
}
function is_error_redeclaration(ex) {
return ex.name == "SyntaxError" && /already been declared|redeclaration/.test(ex.message);
}
function is_error_destructuring(ex) {
return ex.name == "TypeError" && /^Cannot destructure /.test(ex.message);
return ex.name == "TypeError" && /^Cannot (destructure|read propert)/.test(ex.message);
}
function is_error_class_constructor(ex) {
@@ -2351,6 +2408,8 @@ function is_error_getter_only_property(ex) {
}
function patch_try_catch(orig, toplevel) {
var patched = Object.create(null);
var patches = [];
var stack = [ {
code: orig,
index: 0,
@@ -2388,7 +2447,7 @@ function patch_try_catch(orig, toplevel) {
"throw " + match[1] + ";",
].join("\n");
}
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw;
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw + "var UFUZZ_ERROR;";
var result = run_code(new_code, toplevel);
if (!sandbox.is_error(result)) {
if (!stack.filled && match[1]) stack.push({
@@ -2400,27 +2459,35 @@ function patch_try_catch(orig, toplevel) {
offset += insert.length;
code = new_code;
} else if (is_error_in(result)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("invalid `in`");');
} else if (is_error_tdz(result)) {
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("TDZ");');
} else if (is_error_spread(result)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("spread not iterable");' + orig.slice(index);
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("spread not iterable");');
} else if (is_error_recursion(result)) {
index = result.ufuzz_try;
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
patch(result.ufuzz_try, 'throw new Error("skipping infinite recursion");');
} else if (is_error_set_property(result)) {
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("cannot set property");');
} else if (is_error_destructuring(result)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("cannot destructure");' + orig.slice(index);
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("cannot destructure");');
} else if (is_error_class_constructor(result)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("missing new for class");' + orig.slice(index);
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("missing new for class");');
} else if (is_error_getter_only_property(result)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("setting getter-only property");' + orig.slice(index);
patch(result.ufuzz_catch, result.ufuzz_var + ' = new Error("setting getter-only property");');
}
}
stack.filled = true;
}
if (patches.length) return patches.reduce(function(code, patch) {
var index = patch[0];
return code.slice(0, index) + patch[1] + code.slice(index);
}, orig);
function patch(index, code) {
if (patched[index]) return;
patched[index] = true;
patches.unshift([ index, code ]);
}
}
var beautify_options = {
@@ -2444,10 +2511,13 @@ if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && sandbox.is_error(sandbox.r
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
};
}
var bug_async_class_await = SUPPORT.async && SUPPORT.class_field && sandbox.is_error(sandbox.run_code("var await; async function f() { class A { static p = await; } }"));
var bug_class_static_await = SUPPORT.async && SUPPORT.class_field && sandbox.is_error(sandbox.run_code("var await; class A { static p = await; }"));
var bug_class_static_nontrivial = SUPPORT.class_field && sandbox.is_error(sandbox.run_code("class A { static 42; static get 42() {} }"));
var bug_for_of_async = SUPPORT.for_await_of && sandbox.is_error(sandbox.run_code("var async; for (async of []);"));
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && sandbox.is_error(sandbox.run_code("try {} catch (e) { for (var e of []); }"));
var bug_static_class_field = SUPPORT.class_field && sandbox.is_error(sandbox.run_code("class A { static 42; static get 42() {} }"));
var bug_proto_stream = function(ex) {
return ex.name == "TypeError" && ex.message == "callback is not a function";
}
if (SUPPORT.destructuring && sandbox.is_error(sandbox.run_code("console.log([ 1 ], {} = 2);"))) {
beautify_options.output.v8 = true;
minify_options.forEach(function(o) {
@@ -2478,11 +2548,17 @@ for (var round = 1; round <= num_iterations; round++) {
println();
// ignore v8 parser bug
return bug_async_arrow_rest(result)
// ignore Node.js `__proto__` quirks
|| bug_proto_stream(result)
// ignore runtime platform bugs
|| result.message == "Script execution aborted.";
})) continue;
minify_options.forEach(function(options) {
var o = JSON.parse(options);
if (async && has_await) {
o.module = true;
options = JSON.stringify(o);
}
var toplevel = sandbox.has_toplevel(o);
o.validate = true;
uglify_code = UglifyJS.minify(original_code, o);
@@ -2495,6 +2571,8 @@ for (var round = 1; round <= num_iterations; round++) {
var uglify_erred = sandbox.is_error(uglify_result);
// ignore v8 parser bug
if (!ok && uglify_erred && bug_async_arrow_rest(uglify_result)) ok = true;
// ignore Node.js `__proto__` quirks
if (!ok && uglify_erred && bug_proto_stream(uglify_result)) ok = true;
// ignore runtime platform bugs
if (!ok && uglify_erred && uglify_result.message == "Script execution aborted.") ok = true;
// handle difference caused by time-outs
@@ -2532,55 +2610,34 @@ for (var round = 1; round <= num_iterations; round++) {
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
}
}
if (!ok && original_erred && uglify_erred && (
// ignore difference in error message caused by `in`
is_error_in(original_result) && is_error_in(uglify_result)
// ignore difference in error message caused by Temporal Dead Zone
if (!ok && original_erred && uglify_erred && original_result.name == "ReferenceError" && uglify_result.name == "ReferenceError") ok = true;
// ignore difference due to implicit strict-mode in `class`
if (!ok && /\bclass\b/.test(original_code)) {
var original_strict = run_code('"use strict";\n' + original_code, toplevel);
if (uglify_erred && /^(Syntax|Type)Error$/.test(uglify_result.name)) {
ok = sandbox.is_error(original_strict);
} else {
ok = sandbox.same_stdout(original_strict, uglify_result);
}
}
|| is_error_tdz(original_result) && is_error_tdz(uglify_result)
// ignore difference in error message caused by spread syntax
|| is_error_spread(original_result) && is_error_spread(uglify_result)
// ignore difference in error message caused by destructuring assignment
|| is_error_set_property(original_result) && is_error_set_property(uglify_result)
// ignore difference in error message caused by `import` symbol redeclaration
if (!ok && original_erred && uglify_erred && /\bimport\b/.test(original_code)) {
if (is_error_redeclaration(original_result) && is_error_redeclaration(uglify_result)) ok = true;
}
|| /\bimport\b/.test(original_code) && is_error_redeclaration(original_result) && is_error_redeclaration(uglify_result)
// ignore difference in error message caused by destructuring
|| is_error_destructuring(original_result) && is_error_destructuring(uglify_result)
// ignore difference in error message caused by call on class
|| is_error_class_constructor(original_result) && is_error_class_constructor(uglify_result)
// ignore difference in error message caused by setting getter-only property
|| is_error_getter_only_property(original_result) && is_error_getter_only_property(uglify_result)
)) ok = true;
// ignore difference due to `__proto__` assignment
if (!ok && /\b__proto__\b/.test(original_code)) {
var original_proto = run_code("(" + patch_proto + ")();\n" + original_code, toplevel);
var uglify_proto = run_code("(" + patch_proto + ")();\n" + uglify_code, toplevel);
ok = sandbox.same_stdout(original_proto, uglify_proto);
}
// ignore difference in error message caused by `in`
if (!ok && original_erred && uglify_erred) {
if (is_error_in(original_result) && is_error_in(uglify_result)) ok = true;
}
// ignore difference in error message caused by spread syntax
if (!ok && original_erred && uglify_erred) {
if (is_error_spread(original_result) && is_error_spread(uglify_result)) ok = true;
}
// ignore difference in depth of termination caused by infinite recursion
if (!ok && original_erred && is_error_recursion(original_result)) {
if (!uglify_erred || is_error_recursion(uglify_result)) ok = true;
}
// ignore difference in error message caused by destructuring
if (!ok && original_erred && uglify_erred) {
if (is_error_destructuring(original_result) && is_error_destructuring(uglify_result)) ok = true;
}
// ignore difference in error message caused by call on class
if (!ok && original_erred && uglify_erred) {
if (is_error_class_constructor(original_result) && is_error_class_constructor(uglify_result)) {
ok = true;
}
}
// ignore difference in error message caused by setting getter-only property
if (!ok && original_erred && uglify_erred) {
if (is_error_getter_only_property(original_result) && is_error_getter_only_property(uglify_result)) {
ok = true;
}
}
// ignore errors above when caught by try-catch
if (!ok) {
var orig_skipped = patch_try_catch(original_code, toplevel);

View File

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