Compare commits

...

402 Commits

Author SHA1 Message Date
Alex Lam S.L
38c3bcf9a0 v3.9.1 2020-04-15 17:26:30 +08:00
Alex Lam S.L
6e9afdc94f prevent input source map mutation (#3781)
fixes #3780
2020-04-15 17:25:58 +08:00
Alex Lam S.L
c4d28e3b2a expand testing on Node.js versions (#3779) 2020-04-14 10:13:42 +08:00
Alex Lam S.L
77261e1ee0 v3.9.0 2020-04-13 13:45:02 +01:00
Alex Lam S.L
903a5df9a5 fix corner case in inline (#3778)
fixes #3777
2020-04-11 19:54:26 +08:00
Alex Lam S.L
c810ecd081 improve handling of eval (#3776)
closes #3768
2020-04-11 06:36:17 +08:00
Alex Lam S.L
dce9dfce0e fix corner case in reduce_vars (#3775)
fixes #3774
2020-04-11 02:19:38 +08:00
Alex Lam S.L
3d72663689 add tests for eval() (#3769)
closes #3768
2020-04-11 00:36:53 +08:00
Alex Lam S.L
a2b16e89a4 fix corner cases in inline (#3773)
fixes #3770
fixes #3771
fixes #3772
2020-04-11 00:34:45 +08:00
Alex Lam S.L
b35f4c5a83 enhance inline (#3767) 2020-04-10 10:48:24 +08:00
Alex Lam S.L
41eb4f1725 workaround intermittent nodejs.org corruptions (#3766) 2020-04-07 08:40:38 +08:00
Alex Lam S.L
94bc221669 fix export of PATH to Node.js (#3765) 2020-04-07 01:14:16 +08:00
Alex Lam S.L
822d298a55 fix Github Actions retry logic (#3763) 2020-04-06 22:16:48 +08:00
Alex Lam S.L
273c6020ba expand ufuzz patterns (#3761) 2020-04-05 22:12:46 +08:00
Alex Lam S.L
1b07f64057 enhance inline (#3760) 2020-04-05 10:42:23 +08:00
Alex Lam S.L
80d9c44b22 improve resilience against nodejs.org failures (#3759) 2020-04-03 02:49:38 +08:00
Alex Lam S.L
dc0cd088cf fix corner case in evaluate & unsafe_math (#3756)
fixes #3755
2020-03-30 19:13:14 +08:00
Alex Lam S.L
c69c026728 improve resilience against nodejs.org failures (#3758) 2020-03-30 10:20:13 +08:00
Alex Lam S.L
b5f4e1187f handle single-field segments (#3757) 2020-03-30 06:39:32 +08:00
Alex Lam S.L
827bcec186 handle source-map operations internally (#3754) 2020-03-28 22:18:56 +08:00
Alex Lam S.L
d105ab9722 v3.8.1 2020-03-28 01:04:40 +08:00
Alex Lam S.L
b39228892d fix line accounting in multi-line strings (#3752)
fixes #3748
2020-03-21 07:17:41 +08:00
Alex Lam S.L
ff72eaa3c3 improve --reduce-test (#3742)
- ignore difference in error messages
- improve readability on trailing whitespace differences
- improve performance & quality via `console.log()` insertions
2020-03-21 05:50:41 +08:00
Alex Lam S.L
0a1c9b34ce fix corner case in evaluate & ie8 (#3751)
fixes #3750
2020-03-21 00:55:24 +08:00
Alex Lam S.L
03e968be62 improve suspicious option detection (#3749) 2020-03-13 04:03:47 +08:00
Alex Lam S.L
421bb7083a fix corner case in unused (#3747)
fixes #3746
2020-03-06 18:27:42 +00:00
Alex Lam S.L
bdc8ef2218 fix corner case in collapse_vars (#3745)
fixes #3744
2020-03-06 18:27:06 +00:00
Alex Lam S.L
bca52fcba2 speed up CI (#3741) 2020-03-02 22:07:30 +08:00
Alex Lam S.L
d6d31cbb5a improve AST fuzzing (#3740) 2020-03-02 19:38:30 +08:00
Alex Lam S.L
a051846d22 fix corner case in evaluate (#3739)
fixes #3738
2020-03-01 20:34:31 +00:00
Alex Lam S.L
3485472866 avoid reducing setter argument (#3737) 2020-03-01 05:04:21 +00:00
Alex Lam S.L
c8d60d6983 detect toplevel option properly (#3735)
fixes #3730
2020-02-29 17:33:48 +00:00
Alex Lam S.L
6092bf23de fix corner case in evaluate (#3729) 2020-02-19 00:41:10 +00:00
Alex Lam S.L
7052ce5aef fix corner case in evaluate (#3728)
- augment `ufuzz` for further `RegExp` testing
2020-02-18 19:35:37 +00:00
Alex Lam S.L
d13b71297e v3.8.0 2020-02-18 20:32:37 +08:00
Alex Lam S.L
457f958af3 improve --reduce-test (#3727)
- print out Node.js and OS information
2020-02-17 20:56:22 +00:00
Alex Lam S.L
53517db3e4 speed up --reduce-test (#3726)
- avoid pathological test case branches via adaptive time-out
- use initial test case elapsed time to adjust maximum time-out
- index output cache using hash instead of raw source
2020-02-17 15:35:07 +00:00
Alex Lam S.L
c13caf4876 speed up --reduce-test via result caching (#3725) 2020-02-15 22:43:34 +00:00
kzc
fbfa6178a6 improve --reduce-test (#3722)
- hoist body of functions and IIFEs
- simplify var declarations
2020-02-15 20:22:33 +00:00
Alex Lam S.L
5315dd95b0 minor cleanup (#3723) 2020-02-15 17:55:26 +00:00
Marco Gonzalez
31a7bf2a22 Updated "Output options" > "comments" in README.md (#3717)
Expanded the current documentation to include:

- What the value of `"some"` means based on `lib/output.js`.
- Information about the `Function` overload parameters and expected output.
2020-02-15 15:10:58 +00:00
Alex Lam S.L
f0a29902ac enhance properties (#3721) 2020-02-15 13:04:44 +00:00
Alex Lam S.L
0d820e4c0a workaround RegExp formatting bugs (#3720) 2020-02-15 05:26:48 +00:00
Alex Lam S.L
f01f580d6c improve --reduce-test (#3719)
- cover missing cases when eliminating unreferenced labels
- format multi-line outputs correctly
2020-02-14 02:47:20 +00:00
Alex Lam S.L
c01ff76288 improve code reuse (#3718) 2020-02-13 05:16:10 +00:00
Alex Lam S.L
83a42716c3 fix corner case in unused (#3716) 2020-02-12 23:46:16 +00:00
Alex Lam S.L
2557148bba increase mocha --reduce-test timeout (#3715) 2020-02-12 02:25:04 +00:00
Alex Lam S.L
dd22eda888 enhance evaluate (#3714) 2020-02-12 01:01:17 +00:00
Alex Lam S.L
f4c77886e7 add test for --reduce-test (#3712) 2020-02-09 23:21:46 +00:00
Alex Lam S.L
df547ffd97 improve test reduction (#3711)
- scan `AST_SymbolFunarg`
- scan `console.log(...)`
2020-02-09 20:42:36 +00:00
Alex Lam S.L
70551febc8 improve test/reduce (#3710)
- suppress several instances of malformed AST generation
- improve resilience & reporting against malformed ASTs
2020-02-09 08:07:55 +00:00
Alex Lam S.L
44499a6643 fix corner cases in test/reduce (#3709) 2020-02-07 02:41:07 +00:00
Alex Lam S.L
470a7d4df1 improve reduction of AST_BlockStatement (#3708) 2020-02-06 21:20:05 +00:00
Alex Lam S.L
551420132c export missing API for AST manipulation (#3707) 2020-02-06 18:46:25 +00:00
kzc
b0040ba654 implement CLI --reduce-test and reduce tests in ufuzz (#3705) 2020-02-06 02:50:59 +00:00
Alex Lam S.L
c93ca6ee53 fix corner case in ie8 & reduce_vars (#3706)
fixes #3703
2020-02-05 20:03:22 +00:00
Alex Lam S.L
df506439b1 fix corner case in sequences (#3704)
fixes #3703
2020-02-04 04:57:32 +00:00
Alex Lam S.L
36b2d35bf3 v3.7.7 2020-02-02 00:24:50 +00:00
Alex Lam S.L
79c60032a5 fix corner case in collapse_vars (#3701)
fixes #3700
2020-01-30 09:04:44 +08:00
Alex Lam S.L
a3754068dd fix corner case in collapse_vars (#3699)
fixes #3698
2020-01-30 00:08:53 +08:00
Alex Lam S.L
2ba5f391e0 enhance collapse_vars (#3697) 2020-01-29 08:52:20 +08:00
Alex Lam S.L
87119e44a0 fix corner case in sign propagation (#3696)
- migrate de-facto functionality to `evaluate`

fixes #3695
2020-01-28 22:44:18 +08:00
Alex Lam S.L
b499e03f82 enhance conditionals (#3694) 2020-01-28 12:33:21 +08:00
Alex Lam S.L
a478f275e4 enhance sequences (#3693) 2020-01-28 09:58:01 +08:00
Alex Lam S.L
e9e76dcf04 fix corner case in string concatenations (#3692)
- migrate de-facto compression to `conditionals` & `strings`

fixes #3689
2020-01-28 07:33:11 +08:00
Alex Lam S.L
0dcedad2d5 fix corner case in booleans (#3691)
fixes #3690
2020-01-28 02:04:44 +08:00
Alex Lam S.L
36a430cd1e v3.7.6 2020-01-19 11:02:58 +00:00
Alex Lam S.L
41a6eb892a fix corner case in evaluate (#3685)
fixes #3684
2020-01-16 01:51:37 +08:00
Alex Lam S.L
91d87ae663 fix corner case in unsafe_math (#3683)
fixes #3682
2020-01-15 04:05:58 +08:00
Alex Lam S.L
5beb7e4797 v3.7.5 2020-01-12 11:12:11 +08:00
Alex Lam S.L
46caaa82ba enhance collapse_vars (#3680)
closes #3679
2020-01-10 04:28:43 +08:00
Alex Lam S.L
5d258259a4 introduce --output-opts CLI option (#3678)
closes #3675
2020-01-08 20:44:03 +08:00
Alex Lam S.L
14c35739dd fix corner case in unsafe_math (#3677)
fixes #3676
2020-01-08 10:28:10 +08:00
Alex Lam S.L
f5ceff6e4b fix corner case in unused (#3674)
fixes #3673
2020-01-07 20:06:25 +08:00
Alex Lam S.L
4d6771b9b1 fix corner case in collapse_vars (#3672)
fixes #3671
2020-01-07 19:34:16 +08:00
Alex Lam S.L
d17191111a v3.7.4 2020-01-07 07:59:54 +08:00
Alex Lam S.L
0ff607cb80 improve ufuzz false positive detection (#3670) 2020-01-06 11:26:15 +08:00
Alex Lam S.L
1988495d71 fix corner case in conditionals (#3669)
fixes #3668
2020-01-04 09:24:28 +08:00
Alex Lam S.L
fdc10086da fix corner case in reduce_vars (#3667)
fixes #3666
2020-01-03 19:28:47 +08:00
Alex Lam S.L
746f5f6c62 fix corner case in unused (#3665)
fixes #3664
2020-01-01 20:24:30 +08:00
Alex Lam S.L
d83d3d741a enhance unused (#3662) 2019-12-31 23:39:24 +08:00
Alex Lam S.L
99ac73a635 enhance booleans (#3661) 2019-12-31 13:10:05 +08:00
Alex Lam S.L
a2e4c2fd97 enhance evaluate (#3660) 2019-12-31 11:51:21 +08:00
Alex Lam S.L
94785e8e14 fix corner case in booleans (#3659)
fixes #3658
2019-12-31 09:57:35 +08:00
Alex Lam S.L
4dbdac9c31 enhance booleans (#3657) 2019-12-30 22:41:11 +08:00
Alex Lam S.L
78c8efd851 fix corner case in evaluate (#3656)
fixes #3655
2019-12-29 21:16:53 +08:00
Alex Lam S.L
af310ba2d0 fix corner case in evaluate (#3654)
fixes #3653
2019-12-29 02:50:57 +00:00
Alex Lam S.L
2f3930d1b9 fix corner case in collapse_vars (#3652)
fixes #3651
2019-12-29 00:57:59 +00:00
Alex Lam S.L
d1a78920d9 workaround firefox asm.js quirks (#3650)
fixes #3636
2019-12-28 23:14:53 +00:00
Alex Lam S.L
d9cd3d33c8 enhance evaluate (#3649) 2019-12-28 20:26:15 +00:00
Alex Lam S.L
22b47cdd63 improve unicode handling (#3648) 2019-12-28 18:06:51 +00:00
Alex Lam S.L
4cf612dc9f increase mocha default timeout (#3647)
closes #3640
2019-12-28 02:32:22 +00:00
Alex Lam S.L
a19d31dd33 fix corner case in unsafe (#3646) 2019-12-27 14:24:54 +00:00
Alex Lam S.L
01d6e0f223 v3.7.3 2019-12-27 06:11:29 +08:00
Alex Lam S.L
ab050e7a94 fix corner case in directives (#3645) 2019-12-25 00:55:39 +00:00
Alex Lam S.L
75aa6ef848 enhance conditionals (#3643) 2019-12-22 04:29:32 +00:00
Alex Lam S.L
519a00bd8a fix corner case in collapse_vars (#3642)
fixes #3641
2019-12-22 01:08:56 +00:00
Alex Lam S.L
3ff0feddee suppress false positives from fuzzer (#3638) 2019-12-16 17:32:47 +02:00
Alex Lam S.L
74396acc86 fix corner case in loops (#3635)
fixes #3634
2019-12-11 06:39:46 +08:00
Alex Lam S.L
036bca980c enhance loops (#3633) 2019-12-10 12:57:47 +00:00
Alex Lam S.L
18c2b1841b fix corner case in reduce_vars (#3632)
fixes #3631
2019-12-10 09:45:51 +00:00
Alex Lam S.L
fe19ab7c57 v3.7.2 2019-12-08 15:36:18 +00:00
Alex Lam S.L
9074f05129 fix corner case in collapse_vars (#3629)
fixes #3628
2019-12-05 05:08:37 +08:00
Alex Lam S.L
04fbb1f949 avoid collision with HTML comments (#3625)
fixes #3624
2019-12-05 02:43:25 +08:00
Alex Lam S.L
bf7e4ca1a3 fix corner case in collapse_vars (#3627)
fixes #3626
2019-12-05 00:59:57 +08:00
Alex Lam S.L
d68ddc31f9 fix corner case in reduce_vars (#3623)
fixes #3622
2019-12-04 20:24:55 +08:00
Alex Lam S.L
500e31e03b enhance collapse_vars (#3621) 2019-12-02 15:25:38 +08:00
Alex Lam S.L
bef856addb fix corner case in keep_fargs (#3620)
fixes #3619
2019-12-02 12:28:17 +08:00
Alex Lam S.L
9a6faf365b fix corner cases in keep_fargs & unused (#3618) 2019-12-02 06:43:54 +08:00
Alex Lam S.L
e915832a36 enhance unused (#3617) 2019-12-01 18:10:37 +08:00
Alex Lam S.L
0593892d6e enhance collapse_vars (#3616) 2019-12-01 02:31:04 +08:00
Alex Lam S.L
b866a23671 v3.7.1 2019-11-30 06:02:09 +08:00
Alex Lam S.L
1283d73853 fix corner case in parsing directives (#3615) 2019-11-29 18:57:29 +08:00
Alex Lam S.L
1b61a81b5d enhance collapse_vars (#3613) 2019-11-29 17:45:49 +08:00
Alex Lam S.L
5a88c30d65 enhance assignments (#3612) 2019-11-28 07:40:34 +08:00
Alex Lam S.L
168ae747ad enhance collapse_vars (#3611) 2019-11-28 03:57:10 +08:00
Alex Lam S.L
d4b7010678 fix corner case in unsafe_regexp (#3609) 2019-11-27 17:35:21 +08:00
Alex Lam S.L
e27493f3c2 fix corner case in inline (#3608) 2019-11-27 14:54:36 +08:00
Alex Lam S.L
292d1de363 use stable Node.js version for fuzzing (#3605) 2019-11-26 02:11:11 +08:00
Alex Lam S.L
6768e6578f inline functions with directives more effectively (#3604) 2019-11-26 01:51:04 +08:00
Alex Lam S.L
48a0f6fe41 enhance unsafe_math (#3603) 2019-11-25 21:14:13 +08:00
Alex Lam S.L
81caadb709 enhance collapse_vars (#3602) 2019-11-20 12:54:49 +08:00
Alex Lam S.L
d959e0b86f fix corner case in if_return (#3601)
fixes #3600
2019-11-19 15:45:20 +08:00
Alex Lam S.L
67278e76c8 fix corner case in unused (#3599)
fixes #3598
2019-11-19 04:26:41 +08:00
Alex Lam S.L
c289ba1139 fix corner case in collapse_vars (#3597)
fixes #3596
2019-11-19 02:30:52 +08:00
Alex Lam S.L
02cc4a0d03 v3.7.0 2019-11-18 20:21:07 +08:00
Alex Lam S.L
4e06e1ca34 fix corner case in inline (#3595) 2019-11-18 15:04:55 +08:00
Alex Lam S.L
644f65feca fix corner case in unsafe_math (#3594)
fixes #3593
2019-11-18 13:44:13 +08:00
Alex Lam S.L
8504a4ea0e fix corner case in reduce_funcs (#3592) 2019-11-17 11:19:42 +08:00
Alex Lam S.L
10c1a78772 fix corner case in collapse_vars (#3591) 2019-11-17 05:24:02 +08:00
Alex Lam S.L
a6a0319f1c compress empty for-in loops (#3590) 2019-11-17 02:36:42 +08:00
Alex Lam S.L
d1b2ecec27 refine precision limits on unsafe_math (#3589) 2019-11-17 01:16:42 +08:00
Alex Lam S.L
552be61c4d introduce eager evaluation (#3587) 2019-11-16 06:10:47 +08:00
Alex Lam S.L
dcfc4aca5b minor clean-ups (#3588) 2019-11-16 00:40:22 +08:00
Alex Lam S.L
4027f87717 migrate to GitHub Actions (#3586) 2019-11-14 10:48:32 +08:00
Alex Lam S.L
910799ca99 fix corner case in switches (#3585) 2019-11-14 02:29:55 +08:00
Alex Lam S.L
4bd36dc8da enhance unused (#3584) 2019-11-13 21:44:44 +08:00
Alex Lam S.L
ab15c40770 enhance switches (#3583) 2019-11-13 20:03:48 +08:00
Alex Lam S.L
fe65ce9658 fix corner case in collapse_vars (#3582)
fixes #3581
2019-11-13 16:45:16 +08:00
Alex Lam S.L
d6fd18d0b0 enhance evaluate & inline (#3580) 2019-11-13 04:17:09 +08:00
Alex Lam S.L
0d17c5b0fa v3.6.9 2019-11-12 22:50:52 +08:00
Alex Lam S.L
5b20bad4b3 fix corner case in dead_code (#3579)
fixes #3578
2019-11-12 05:16:14 +08:00
Alex Lam S.L
765a06340f enable cache on GitHub Actions (#3570) 2019-11-10 09:06:48 +08:00
Alex Lam S.L
5045e140b1 fix corner case in conditionals (#3577)
fixes #3576
2019-11-09 00:53:15 +08:00
Alex Lam S.L
10648c9af6 enhance dead_code (#3575) 2019-11-08 13:45:28 +08:00
Alex Lam S.L
87e67ec299 fix corner case in collapse_vars (#3574)
fixes #3573
2019-11-07 20:38:03 +08:00
Alex Lam S.L
61a0dad9fe v3.6.8 2019-11-06 13:52:58 +08:00
Alex Lam S.L
3e2c51a4da enhance collapse_vars (#3572) 2019-11-05 18:15:28 +08:00
Alex Lam S.L
0e29ad5eb9 fix corner case in evaluate (#3569) 2019-11-04 13:13:48 +08:00
Alex Lam S.L
0f2687ecfc v3.6.7 2019-11-02 13:32:05 +08:00
Alex Lam S.L
1c0defdc03 enhance unsafe evaluate (#3564) 2019-11-02 03:34:32 +08:00
Alex Lam S.L
dcbf2236c7 more tests for #3562 (#3565) 2019-11-02 03:34:20 +08:00
Alex Lam S.L
24bb288832 fix corner case in collapse_vars (#3563)
fixes #3562
2019-11-01 22:38:19 +08:00
Alex Lam S.L
6ad8e1081f v3.6.6 2019-11-01 13:40:03 +08:00
Alex Lam S.L
815eff1f7c enhance if_return (#3560) 2019-11-01 02:08:31 +08:00
Alex Lam S.L
1e9b576ee9 fix corner case in evaluate (#3559)
fixes #3558
2019-11-01 00:01:25 +08:00
Alex Lam S.L
3797458365 enhance conditionals (#3557) 2019-10-31 09:33:46 +08:00
Alex Lam S.L
1858c2018c enhance typeofs (#3556) 2019-10-31 08:00:04 +08:00
Alex Lam S.L
ec7f071272 fix corner case in dead_code (#3553)
fixes #3552
2019-10-30 14:21:22 +08:00
Alex Lam S.L
f1eb03f2c0 enhance dead_code (#3551) 2019-10-30 06:34:54 +08:00
Alex Lam S.L
0f4cfa877a fix corner case in comments (#3550) 2019-10-30 03:49:39 +08:00
Alex Lam S.L
1d5c2becbd enhance evaluate (#3549) 2019-10-29 19:51:55 +08:00
Alex Lam S.L
22a09ea7c5 fix corner case in unsafe_math (#3548)
fixes #3547
2019-10-29 17:06:57 +08:00
Alex Lam S.L
bad664c632 compress object literals (#3546) 2019-10-29 16:53:48 +08:00
Alex Lam S.L
8a191c0a84 v3.6.5 2019-10-29 12:55:28 +08:00
Alex Lam S.L
83fb8b4ca1 fix corner case in ie8 (#3543)
fixes #3542
2019-10-28 23:54:27 +08:00
Alex Lam S.L
f38e31bd1e fix corner case in evaluate (#3540)
fixes #3539
2019-10-28 19:56:42 +08:00
Alex Lam S.L
24e8b47977 improve ufuzz resilience (#3541) 2019-10-28 18:08:51 +08:00
Alex Lam S.L
95618793a4 fix corner case in ufuzz (#3538) 2019-10-28 16:04:07 +08:00
Alex Lam S.L
2f3b460212 fix & enhance unsafe_math (#3537)
closes #3535
fixes #3536
2019-10-28 13:37:08 +08:00
Alex Lam S.L
06e135e35f migrate CI workaround (#3534) 2019-10-27 17:29:54 +08:00
Alex Lam S.L
ebbf3d4a51 improve ufuzz resilience (#3533) 2019-10-27 14:17:35 +08:00
Alex Lam S.L
a270ba6b59 fix corner cases in unsafe_math (#3532)
fixes #3531
2019-10-27 08:25:11 +08:00
Alex Lam S.L
37f35e4ac2 prevent tty truncation in test/compress (#3530) 2019-10-27 05:00:21 +08:00
Alex Lam S.L
50a578c1f6 compress arithmetic expressions further (#3529) 2019-10-27 03:07:07 +08:00
Alex Lam S.L
85237b08d4 fix corner case in collapse_vars (#3527)
fixes #3526
2019-10-26 05:41:02 +08:00
Alex Lam S.L
27b159e711 separate ufuzz job failures (#3525) 2019-10-25 02:06:29 +08:00
Alex Lam S.L
82b3eed5ef fix corner case in ie8 & mangle (#3524)
fixes #3523
2019-10-24 23:43:19 +08:00
Alex Lam S.L
0f7aa41e33 fix corner case in collapse_vars (#3521)
fixes #3520
2019-10-24 01:13:57 +08:00
Alex Lam S.L
370c8e0385 v3.6.4 2019-10-23 15:38:05 +08:00
Alex Lam S.L
4240fba9b8 fix corner cases in unused (#3519) 2019-10-23 06:46:05 +08:00
Alex Lam S.L
267bc70d33 fix corner case in unused (#3517)
fixes #3515
2019-10-23 01:58:40 +08:00
Alex Lam S.L
a53ab99378 fix corner case in side_effects (#3514)
fixes #3512
2019-10-23 01:04:00 +08:00
Alex Lam S.L
02308a7b56 fix corner case in reduce_vars (#3510)
fixes #3509
2019-10-22 20:36:05 +08:00
Alex Lam S.L
0b3705e82f fix corner cases in inline (#3507)
fixes #3506
2019-10-22 15:41:55 +08:00
Alex Lam S.L
da5a21b240 fix GitHub Actions script for fuzzing (#3504) 2019-10-21 04:30:00 +08:00
Alex Lam S.L
5bd0cf8633 enable GitHub Actions (#3503) 2019-10-21 04:11:14 +08:00
Alex Lam S.L
9199ab5846 minor tweaks (#3502) 2019-10-20 15:19:19 +08:00
Alex Lam S.L
ca6dce43fe fix corner case in collapse_vars (#3501) 2019-10-20 03:53:20 +08:00
Alex Lam S.L
543dd7d3d7 fix corner case in comments (#3500) 2019-10-20 03:21:30 +08:00
Alex Lam S.L
6b4886c908 v3.6.3 2019-10-19 14:28:11 +08:00
Alex Lam S.L
0201cb4b52 fix corner case in unused (#3499)
fixes #3497
2019-10-18 20:08:05 +08:00
Alex Lam S.L
cd072317d0 fix corner case in unused (#3496)
fixes #3495
2019-10-18 17:09:43 +08:00
Alex Lam S.L
0785a15ace fix corner case in dead_code & ie8 (#3494)
fixes #3493
2019-10-17 09:58:05 +08:00
Alex Lam S.L
b1279a46d9 fix corner case in sequences (#3491)
fixes #3490
2019-10-17 09:57:50 +08:00
Alex Lam S.L
b571619d31 handle throw of non-Errors gracefully (#3492) 2019-10-17 06:29:02 +08:00
Alex Lam S.L
7b5350b459 tweak Travis CI execution environment (#3489) 2019-10-16 15:47:06 +08:00
Alex Lam S.L
1549db70e6 fix corner case in ie8 (#3487)
fixes #3486
2019-10-16 12:18:27 +08:00
Alex Lam S.L
8ff9a3c8fb fix corner cases in ie8 (#3485)
fixes #3484
2019-10-16 06:37:40 +08:00
Alex Lam S.L
91cae51d8f fix corner case in evaluate & ie8 (#3483)
fixes #3482
2019-10-16 01:09:16 +08:00
Alex Lam S.L
8af2f5fbcf fix corner case in rename (#3481)
fixes #3480
2019-10-15 19:44:07 +08:00
Alex Lam S.L
86a8016323 fix corner case in ie8 & mangle (#3479)
fixes #3478
2019-10-15 17:14:48 +08:00
David xu
009dcdae01 avoid mangling of MutationObserver properties (#3477) 2019-10-15 16:16:43 +08:00
Alex Lam S.L
f86f615d83 fix corner case in ie8 & mangle (#3476)
fixes #3475
2019-10-15 14:18:12 +08:00
Alex Lam S.L
d3d1d11926 fix corner case in ie8 & rename (#3474)
fixes #3473
2019-10-15 07:27:02 +08:00
Alex Lam S.L
736019b767 fix corner cases in ie8 (#3472)
fixes #3471
2019-10-14 18:15:40 +08:00
Alex Lam S.L
a39bdb5840 fix corner case with collapse_vars & ie8 (#3469)
fixes #3468
2019-10-14 13:34:35 +08:00
Alex Lam S.L
e8ab0a44b2 update dependency (#3470) 2019-10-14 13:34:22 +08:00
Alex Lam S.L
c3ca293e6b v3.6.2 2019-10-12 20:19:05 +08:00
Alex Lam S.L
516b67a43b minor tweaks to CI test scripts (#3467) 2019-10-12 05:36:38 +08:00
Alex Lam S.L
eba3a37bb5 fix boolean context detection (#3466)
fixes #3465
2019-10-12 03:42:57 +08:00
Alex Lam S.L
6d57ca1a59 improve source map handling (#3464)
fixes #2947
fixes #3277
fixes #3411
2019-10-11 03:52:33 +08:00
Alex Lam S.L
3320251b4b update benchmark URLs (#3462) 2019-10-11 01:00:09 +08:00
Alex Lam S.L
33c94d3bd9 detect boolean context across IIFEs (#3461) 2019-10-10 09:37:02 +08:00
Alex Lam S.L
b18f717b46 improve readability of --help ast (#3460) 2019-10-10 04:32:32 +08:00
Alex Lam S.L
a0d4b648bb remove extraneous property (#3459)
fixes #3455
2019-10-10 01:36:58 +08:00
Alex Lam S.L
6db880e16d clean up AST_Binary optimisation logic (#3458) 2019-10-09 23:45:41 +08:00
Alex Lam S.L
a82003d6ac v3.6.1 2019-10-07 14:36:46 +08:00
Alex Lam S.L
da9f1622fc report errors correctly in ufuzz (#3456) 2019-10-07 14:36:00 +08:00
Alex Lam S.L
8a4c7077bb account for catch in constant lambda expressions (#3454) 2019-10-06 16:51:37 +08:00
Alex Lam S.L
0a63f2f2b0 workaround V8 RegExp bug (#3453)
fixes #3434
2019-10-06 11:49:39 +08:00
Alex Lam S.L
931ac66638 fix corner case in hoist_props (#3452)
fixes #3440
2019-10-06 10:29:13 +08:00
Alex Lam S.L
35338a100f handle function/variable name collisions correctly (#3451)
fixes #3439
2019-10-06 08:51:38 +08:00
David xu
d57b606e73 exclude mangling of addEventListener parameters (#3445) 2019-10-06 05:29:08 +08:00
Sampson Crowley
00ada04111 facilitate Webpack compatibility (#3435)
Verbose application of `require.resolve` instead of `[].map`
2019-10-06 05:20:47 +08:00
Alex Lam S.L
a31c477fea fix variable scope determination (#3449)
fixes #3444
2019-10-06 05:13:44 +08:00
Alex Lam S.L
bde7418ce1 update & fix dependencies (#3450) 2019-10-06 03:10:12 +08:00
Alex Lam S.L
70bb304a0a v3.6.0 2019-05-30 15:30:00 +08:00
Alex Lam S.L
9d3b1efd86 fix corner case in assignments (#3430)
fixes #3429
2019-05-30 05:01:53 +08:00
Alex Lam S.L
482e1baea3 enhance assignments & unused (#3428)
closes #3427
2019-05-29 01:21:08 +08:00
Alex Lam S.L
e4f5ba1d29 v3.5.15 2019-05-21 14:26:58 +08:00
Alex Lam S.L
b9053c7a25 fix corner case in keep_fargs (#3424)
fixes #3423
2019-05-21 12:55:34 +08:00
Alex Lam S.L
d357a7aabc v3.5.14 2019-05-20 00:13:06 +08:00
Alex Lam S.L
ae77ebe5a5 fix corner case in arguments (#3421)
fixes #3420
2019-05-19 12:59:40 +08:00
Alex Lam S.L
04439edcec v3.5.13 2019-05-17 14:10:33 +08:00
Alex Lam S.L
a246195412 enhance unsafe comparisons (#3419) 2019-05-17 01:28:18 +08:00
Alex Lam S.L
8939a36bc7 reduce false positives from fuzzing (#3417) 2019-05-16 16:15:03 +08:00
Alex Lam S.L
a21c348d93 improve sandbox fidelity (#3415) 2019-05-15 23:26:57 +08:00
Alex Lam S.L
1f0def10eb fix corner case in comparisons (#3414)
fixes #3413
2019-05-15 01:01:18 +08:00
Alex Lam S.L
f87caac9d8 fix corner case in hoist_props (#3412)
fixes #3411
2019-05-14 19:12:00 +08:00
Alex Lam S.L
d538a73250 enhance side_effects (#3410) 2019-05-14 05:26:40 +08:00
Alex Lam S.L
2e4fbdeb08 enhance keep_fargs (#3409) 2019-05-13 21:58:04 +08:00
Alex Lam S.L
3bc7cc82bb v3.5.12 2019-05-12 10:40:13 +08:00
Alex Lam S.L
45fbdbc2dc improve tests (#3408) 2019-05-12 09:44:02 +08:00
Alex Lam S.L
54cb678055 fix corner case in assignments (#3407)
fixes #3406
2019-05-12 03:52:46 +08:00
Alex Lam S.L
e88c439eac improve tests (#3405) 2019-05-11 22:06:14 +08:00
Alex Lam S.L
9fc8cd4076 fix corner case in functions (#3403)
fixes #3402
2019-05-11 18:55:45 +08:00
Alex Lam S.L
5476cb8f05 fix corner case in inline (#3401)
fixes #3400
2019-05-10 01:22:44 +08:00
Alex Lam S.L
6a30e1d6be improve tests (#3399) 2019-05-09 07:18:22 +08:00
Alex Lam S.L
e4881245d9 v3.5.11 2019-05-07 01:45:40 +08:00
Alex Lam S.L
354fec8a9c make enclose & wrap work with sourceMap (#3396)
fixes #3313
2019-05-04 20:25:52 +08:00
Alex Lam S.L
11cdab745d fix corner cases in sourceMap (#3397)
fixes #3255
fixes #3294
2019-05-04 20:08:57 +08:00
Alex Lam S.L
a89d424a0b render comments in custom ASTs gracefully (#3393)
fixes #3246
2019-05-02 13:50:51 +08:00
Alex Lam S.L
429d2b56b7 v3.5.10 2019-05-02 00:01:40 +08:00
Alex Lam S.L
2ea96549c5 unify logging functionality (#3392)
fixes #3253
fixes #3254
2019-04-30 06:32:24 +08:00
Alex Lam S.L
fba008e298 remove blanket safeguard from source-map (#3391)
Things has stabilised since 80a18fe2fa, so it makes sense to remove the unconditional masking for ease of debugging.
2019-04-30 02:40:36 +08:00
Alex Lam S.L
c37a8e927e fix corner case in properties (#3390)
fixes #3389
2019-04-29 17:23:00 +08:00
Alex Lam S.L
413bbe0480 fix corner case in evaluate (#3388)
fixes #3387
2019-04-29 08:55:46 +08:00
Alex Lam S.L
34075fc4c4 v3.5.9 2019-04-27 17:00:58 +08:00
Alex Lam S.L
e5436ca566 enhance side_effects (#3384) 2019-04-25 15:15:50 +08:00
Alex Lam S.L
cfde686eab v3.5.8 2019-04-25 12:33:13 +08:00
Alex Lam S.L
a206964c0a enhance side_effects (#3383) 2019-04-25 04:14:21 +08:00
Alex Lam S.L
c56d89f804 enhance unsafe (#3382) 2019-04-25 02:42:54 +08:00
Alex Lam S.L
c215706350 enhance unsafe comparisons (#3381) 2019-04-25 00:08:08 +08:00
Alex Lam S.L
d3b93ec682 fix corner case in unsafe (#3380) 2019-04-24 22:21:28 +08:00
Alex Lam S.L
6fe20dbe33 enhance comparisons (#3379) 2019-04-24 21:38:55 +08:00
Alex Lam S.L
7ccdf3337b v3.5.7 2019-04-24 14:05:07 +08:00
Alex Lam S.L
dafed54764 fix corner case in reduce_vars (#3378)
fixes #3377
2019-04-24 14:01:01 +08:00
Alex Lam S.L
a84beafd1b fix corner case in assignments (#3376)
fixes #3375
2019-04-24 02:50:15 +08:00
Alex Lam S.L
f01cc1e413 unwind IIFE class patterns (#3373)
fixes #2332
2019-04-21 09:49:07 +08:00
Alex Lam S.L
338dd144b8 v3.5.6 2019-04-21 07:19:29 +08:00
Alex Lam S.L
c719552317 fix corner cases in functions (#3372)
fixes #3371
2019-04-21 02:16:05 +08:00
Alex Lam S.L
855964a87a enhance unsafe evaluate (#3370) 2019-04-20 19:42:41 +08:00
Alex Lam S.L
a438e2fca9 update domprops (#3369)
fixes #2343
fixes #3037
2019-04-20 07:16:14 +08:00
Alex Lam S.L
00833e893a enhance functions (#3368) 2019-04-19 19:01:47 +08:00
Alex Lam S.L
f1a77e4fc0 v3.5.5 2019-04-19 15:22:46 +08:00
Alex Lam S.L
b55a2fd531 fix corner case in functions (#3367)
fixes #3366
2019-04-19 02:55:43 +08:00
Alex Lam S.L
e8a2c0b5bf fix corner case in functions (#3365)
fixes #3364
2019-04-18 17:03:52 +08:00
Alex Lam S.L
21cd7e3f57 reduce test exports (#3361) 2019-04-17 16:19:08 +08:00
Alex Lam S.L
5172ba5f2a introduce functions (#3360)
`var f = function() {};` => `function f() {}`
2019-04-15 22:23:11 +08:00
Alex Lam S.L
a57b069409 v3.5.4 2019-04-10 02:40:42 +08:00
Alex Lam S.L
4454656c3b update dependencies (#3358)
- commander@2.20.0
- semver@6.0.0
2019-04-10 02:39:56 +08:00
Alex Lam S.L
fa43768ce0 v3.5.3 2019-04-01 18:12:03 +08:00
Alex Lam S.L
a74e600fa0 mangle shadowed lambda under ie8 correctly (#3356)
fixes #3355
2019-04-01 15:22:00 +08:00
Ruben Bridgewater
4b21526310 Fix test expectation (#3357)
The test expects a specific precision value that is not met on all V8 versions anymore due to a recent consolidation of different algorithms across the V8 code base.

This makes sure the preceision is tested against one digit less to keep the test working on all V8 versions.

Refs: 98453126c1
Refs: https://github.com/nodejs/node/issues/25060#issuecomment-477953457
2019-03-30 02:08:27 +08:00
Alex Lam S.L
a7a7b1daed v3.5.2 2019-03-23 14:25:14 +08:00
Alex Lam S.L
7436977aa5 fix infinite loop triggered by #3347 (#3354)
fixes #3353
2019-03-23 14:21:54 +08:00
Alex Lam S.L
e3c565b46f v3.5.1 2019-03-21 13:54:14 +08:00
Alex Lam S.L
54b0b49b68 enhance inline (#3352) 2019-03-21 02:58:33 +08:00
Alex Lam S.L
65648d84a5 enhance collapse_vars (#3351) 2019-03-20 23:31:21 +08:00
Alex Lam S.L
fd788590f6 v3.5.0 2019-03-20 18:43:54 +08:00
Alex Lam S.L
143f9054da fix corner case in sequences (#3350) 2019-03-20 14:54:26 +08:00
Alex Lam S.L
f2286c33f1 enhance unsafe for Array (#3349) 2019-03-20 06:37:51 +08:00
Alex Lam S.L
b9615f7a62 improve compress performance (#3348)
fixes #3174
2019-03-20 02:53:04 +08:00
Alex Lam S.L
c520e99eda enhance comparisons (#3347) 2019-03-19 01:34:25 +08:00
Alex Lam S.L
615ae37ca3 introduce assignments (#3345) 2019-03-18 21:28:41 +08:00
Alex Lam S.L
7aa7f21872 fix corner case in evaluate (#3344) 2019-03-18 21:24:42 +08:00
Alex Lam S.L
4430a436eb fix corner case in inline (#3343) 2019-03-17 05:31:40 +08:00
Alex Lam S.L
9707ccdc9f v3.4.10 2019-03-16 00:16:21 +08:00
Alex Lam S.L
cb8f3a2a31 add Node.js 10 to CI tests (#3342) 2019-03-15 16:45:12 +08:00
Alex Lam S.L
8b3259e0c2 fix corner case in reduce_vars (#3341) 2019-03-15 16:06:47 +08:00
Alex Lam S.L
b66f47b8dd update dependencies
- acorn@6.1.1
- commander@2.19.0
- semver@5.6.0
2019-03-15 14:49:48 +08:00
Alex Lam S.L
8d2e6f333e fix function inlining after reduce_vars (#3340)
fixes #3297
2019-03-15 05:45:46 +08:00
Alex Lam S.L
b3ef5e514d enhance evaluate (#3339)
fixes #3299
2019-03-15 02:48:23 +08:00
Alex Lam S.L
627f5fb41e fix corner case with nameCache (#3338)
fixes #3301
2019-03-15 01:15:50 +08:00
Alex Lam S.L
d90777b724 parse mangle.properties.regex in --config-file properly (#3337)
fixes #3315
2019-03-15 00:20:20 +08:00
Alex Lam S.L
e49297e5eb improve usability of pure_funcs (#3336)
fixes #3325
2019-03-14 21:36:45 +08:00
Alex Lam S.L
ebd82b3fb6 fix corner case in collapse_vars (#3334)
fixes #3274
2019-03-14 16:05:56 +08:00
Alex Lam S.L
d074aa6e27 fix corner case in collapse_vars (#3333)
fixes #3247
fixes #3305
fixes #3314
fixes #3327
2019-03-13 23:48:52 +08:00
Alex Lam S.L
b052f62710 fix corner case in reduce_vars (#3332)
fixes #3267
2019-03-13 21:56:38 +08:00
Alex Lam S.L
d4ac84b255 fix corner case in arguments & reduce_vars (#3331)
fixes #3282
2019-03-13 08:46:03 +08:00
Alex Lam S.L
e250396d7e fix corner case in arguments (#3330)
Track modifications to `arguments[i]` under Strict Mode.

fixes #3273
2019-03-13 06:59:53 +08:00
Seul-gi Choi(Chase)
c6fa39b482 Update README.md (#3311)
fix anchor for mangle-options
2019-03-13 05:31:04 +08:00
silverwind
9aae4f2424 make tests compatible with Node.js 12 (#3304)
In Node.js 12, the formatting of console arguments will change slightly.
Previously, a string other than the first argument was formatted using
single quotes if the first argument was non-string. Now, quotes are
never added regardless of position of a string argument.

To make test compatible in all Node.js versions, I work around by
ensuring the first argument to console.log is a string which prevents
the quotes from being added on older versions of Node.js.

Ref: https://github.com/nodejs/node/pull/23162
2019-03-13 04:55:04 +08:00
Alex Lam S.L
008c236137 fix corner case in conditionals (#3329)
fixes #3245
fixes #3257
fixes #3260
fixes #3269
fixes #3271
fixes #3278
fixes #3309
fixes #3319
fixes #3321
2019-03-13 04:28:21 +08:00
Ed S
b1c0664066 Fix typo in warning (#3324)
protoype -> prototype
2019-03-13 02:15:54 +08:00
Alex Lam S.L
ea999b0e92 v3.4.9 2018-08-31 04:28:21 +00:00
Alex Lam S.L
ce7e220de4 fix corner case in conditionals (#3244) 2018-08-30 15:59:05 +08:00
Alex Lam S.L
2bdaca10ae enhance conditionals (#3243) 2018-08-30 01:06:34 +08:00
Alex Lam S.L
aa0029204e fix corner case in reduce_vars (#3241)
fixes #3240
2018-08-29 22:14:25 +08:00
Alex Lam S.L
f352bcec3a fix corner case in collapse_vars (#3239)
fixes #3238
2018-08-29 11:34:34 +08:00
Alex Lam S.L
08514030f4 v3.4.8 2018-08-23 15:27:34 +08:00
Alex Lam S.L
694ca5d045 fix corner case in unused (#3234)
fixes #3233
2018-08-23 06:03:39 +08:00
Alex Lam S.L
57fb58b263 enhance if_return (#3232) 2018-08-21 18:34:16 +08:00
alexlamsl
18c1c9b38a update dependencies
- commander@2.17.1
2018-08-14 17:06:09 +08:00
Alex Lam S.L
5c1ae3662d v3.4.7 2018-08-09 14:47:24 +00:00
Alex Lam S.L
cfebeb2f63 fix corner case in mangle workaround for Safari (#3230)
fixes #3227
2018-08-09 17:34:28 +08:00
Alex Lam S.L
fc78423f1d clean up webkit quirks (#3229) 2018-08-08 16:15:45 +08:00
Alex Lam S.L
2a5277b391 v3.4.6 2018-07-27 11:35:26 +00:00
Alex Lam S.L
d47547dc71 fix corner case in join_vars (#3224) 2018-07-27 19:34:44 +08:00
Alex Lam S.L
304db15a20 fix corner case in ie8 & rename (#3223) 2018-07-26 16:35:43 +08:00
Alex Lam S.L
7cf72b8d66 fix corner case in global_defs (#3218)
fixes #3217
2018-07-19 18:14:36 +08:00
Alex Lam S.L
cea685f8d9 fix corner case in ie8 (#3216)
fixes #3215
2018-07-19 14:45:36 +08:00
Alex Lam S.L
8d4b5344f4 v3.4.5 2018-07-16 18:43:30 +00:00
alexlamsl
34a0ab6f2c improve fuzzing on Travis CI 2018-07-13 02:05:52 +08:00
Alex Lam S.L
bcebacbb9e fix corner cases in preserve_line (#3212) 2018-07-13 01:51:10 +08:00
Alex Lam S.L
018a5a750a v3.4.4 2018-07-09 01:09:56 +00:00
alexlamsl
b468103f26 use nvs for CI testing 2018-07-05 18:49:29 +08:00
Alex Lam S.L
66c126ffde fix corner case in ie8 (#3207)
fixes #3206
2018-07-03 16:44:23 +08:00
Alex Lam S.L
fdee083465 v3.4.3 2018-07-02 06:03:18 +00:00
alexlamsl
5ffc17d4aa fix corner case in unused 2018-07-01 14:34:42 +08:00
alexlamsl
6aa750010f update dependencies
- acorn@5.7.1
- commander@2.16.0
2018-07-01 01:49:43 +08:00
Alex Lam S.L
76df77c08c implement directives (#3203)
fixes #3166
2018-06-28 18:16:49 +08:00
Alex Lam S.L
957d5537a8 improve unsafe comparisons (#3200) 2018-06-28 03:46:19 +08:00
Alex Lam S.L
88c8f4e363 v3.4.2 2018-06-26 01:29:48 +08:00
Alex Lam S.L
ab36b9b10a fix corner case in ie8 (#3198)
fixes #3197
2018-06-24 04:00:36 +08:00
Alex Lam S.L
28330913d8 improve mocha tests (#3195) 2018-06-24 04:00:36 +08:00
Alex Lam S.L
766a4147d4 enhance arguments (#3193)
fixes #3192
2018-06-24 04:00:21 +08:00
Alex Lam S.L
915c7e234d v3.4.1 2018-06-19 18:35:48 +00:00
Alex Lam S.L
e54ddcbb8a fix corner cases in properties (#3189)
fixes #3188
2018-06-19 18:20:11 +08:00
Alex Lam S.L
9e19e63551 general clean-ups (#3175) 2018-06-06 17:50:56 +08:00
Alex Lam S.L
bce7ee5f6a v3.4.0 2018-06-02 05:57:10 +00:00
Jiavan
b39043f3ab re-introduce enclose (#3163)
fixes #2443
2018-06-01 16:47:11 +08:00
Alex Lam S.L
caf96acb08 handle asynchronous test failures (#3164) 2018-05-31 20:21:39 +08:00
Alex Lam S.L
c76749084b update JetStream URL (#3165) 2018-05-31 16:23:49 +08:00
Alex Lam S.L
5843494ee2 v3.3.28 2018-05-29 12:25:42 +00:00
Alex Lam S.L
efa21ae3e6 fix corner case in reduce_vars (#3151) 2018-05-26 05:45:44 +08:00
Alex Lam S.L
24d9633a35 fix corner cases with eval() (#3147)
fixes #3146
2018-05-24 14:29:30 +08:00
Alex Lam S.L
7963b96681 augment tests for inline source maps (#3145) 2018-05-24 02:37:51 +08:00
Alex Lam S.L
8c62d854ce augment tests for RegExp (#3144) 2018-05-23 17:24:13 +08:00
Alex Lam S.L
69931574e1 v3.3.27 2018-05-22 17:09:12 +00:00
Alex Lam S.L
b5af8a1914 fix corner case in reduce_vars (#3141)
fixes #3140
2018-05-21 15:53:51 +08:00
Alex Lam S.L
c14d09ba84 v3.3.26 2018-05-20 17:32:32 +00:00
Alex Lam S.L
4fc39d8dad fix corner case in collapse_vars (#3139) 2018-05-19 05:45:14 +08:00
exvisory
0b7c70f726 Update README.md to clarify --source-map filename option (#3137)
Clarify that the --source-map filename option does NOT change the source map output filename but does set the 'file' attribute within the output source map. This was already documented in the API section of the README so I just copied that to the CLI options section, and a fragment to the CLI summary.
2018-05-18 15:50:36 +08:00
Alex Lam S.L
f72d3029dd v3.3.25 2018-05-12 23:50:40 +00:00
Alex Lam S.L
1a0d6edc81 remove colors dependency (#3133) 2018-05-13 07:50:02 +08:00
Alex Lam S.L
7b59b2f5b2 replace mocha dependency (#3131) 2018-05-11 20:15:34 +08:00
Alex Lam S.L
7bc7704edf fix corner case in reduce_vars (#3129) 2018-05-10 18:45:20 +08:00
Alex Lam S.L
14e712ee80 fix corner case in call binding (#3128)
fixes #3127
2018-05-10 06:16:35 +08:00
Alex Lam S.L
f83adcc995 v3.3.24 2018-05-07 20:17:34 +00:00
Alex Lam S.L
df8a99439a fix various corner cases (#3126)
- augment ufuzz/reminify test options

fixes #3125
2018-05-07 07:36:25 +08:00
Alex Lam S.L
6b91d12ec3 fix corner case in reduce_vars (#3124) 2018-05-06 16:42:35 +08:00
Alex Lam S.L
f37b91879f fix various corner cases (#3123) 2018-05-05 13:17:50 +08:00
Alex Lam S.L
d835c72c80 speed up collapse_vars (#3119) 2018-05-04 18:38:13 +08:00
Alex Lam S.L
c4cebb4b01 fix reduce_vars on nested invocations (#3118) 2018-05-04 06:05:38 +08:00
Alex Lam S.L
d51a00a450 compress AST_Sequence within AST_Call (#3117) 2018-05-03 19:14:56 +08:00
Alex Lam S.L
fc0f168a0c better fix for #3113 (#3115) 2018-05-03 15:51:51 +08:00
Alex Lam S.L
a0ca595c2c fix TreeWalker scan order (#3114)
fixes #3113
2018-05-03 00:27:45 +08:00
Alex Lam S.L
1a314e9f60 improve reduce_vars (#3112)
fixes #3110
2018-05-02 15:11:45 +08:00
Alex Lam S.L
6fcbd5e217 v3.3.23 2018-04-28 17:14:52 +00:00
Alex Lam S.L
22cea023d1 improve numeral compression (#3108) 2018-04-28 02:47:49 +08:00
Alex Lam S.L
70d4477e05 workaround vm context issue in node-chakracore (#3106) 2018-04-27 07:40:34 +08:00
Alex Lam S.L
838f837379 improve general performance (#3104) 2018-04-27 04:30:29 +08:00
Alex Lam S.L
82a8b6f612 improve collapse_vars (#3103) 2018-04-26 19:26:01 +08:00
Alex Lam S.L
69fc7ca8da workaround test failures in Node.js 10 (#3102) 2018-04-26 17:44:37 +08:00
Alex Lam S.L
0a79496e0a workaround stack overflow in ChakraCore (#3101) 2018-04-26 15:02:17 +08:00
Alex Lam S.L
9e87edfc2e better fix for #2506 (#3099) 2018-04-25 04:46:07 +08:00
Alex Lam S.L
27211cf2d5 handle RHS side-effects in collapse_vars (#3097)
fixes #3096
2018-04-24 20:31:50 +08:00
Alex Lam S.L
b5ce199711 improve max_line_len (#3095)
fixes #304
2018-04-24 15:19:45 +08:00
Alex Lam S.L
c71ed91e63 update AST documentation (#3094)
fixes #2622
2018-04-24 14:39:12 +08:00
alexlamsl
f7545d0f1c remove unsupported platform 2018-04-24 13:32:54 +08:00
Alex Lam S.L
59eecb6bf5 v3.3.22 2018-04-20 19:50:16 +00:00
Alex Lam S.L
d83c6490ab fix corner case in strip_func_ids() (#3090) 2018-04-19 04:51:42 +08:00
Alex Lam S.L
7362f57966 improve performance when handling unused variables in collapse_vars (#3084)
fixes #3082
2018-04-15 12:38:31 +08:00
Alex Lam S.L
eaa2c1f6af v3.3.21 2018-04-12 07:08:53 +00:00
Alex Lam S.L
6a916523d4 fix inline of catch-scoped variables (#3077)
fixes #3076
2018-04-11 15:44:43 +08:00
Alex Lam S.L
ba7069d52b suppress hoist_props for embedded assignments (#3074) 2018-04-11 05:19:16 +08:00
Alex Lam S.L
4dd7d0e39b extend hoist_props (#3073)
- handle `AST_Assign` the same way as `AST_VarDef`
- inject `AST_Var` as succeeding statement

fixes #3071
2018-04-11 02:48:15 +08:00
Alex Lam S.L
90199d0a96 extend join_vars on object assignments (#3072) 2018-04-11 01:35:42 +08:00
Alex Lam S.L
b82fd0ad41 handle flow control in loops with reduce_vars (#3069)
fixes #3068
2018-04-10 06:51:03 +08:00
Alex Lam S.L
183da16896 handle pure_funcs under inline & reduce_vars correctly (#3066)
fixes #3065
2018-04-10 02:46:38 +08:00
173 changed files with 28786 additions and 6990 deletions

View File

@@ -2,10 +2,6 @@
<!-- Note: sub-optimal but correct code is not a bug --> <!-- Note: sub-optimal but correct code is not a bug -->
**ES5 or ES6+ input?**
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
**Uglify version (`uglifyjs -V`)** **Uglify version (`uglifyjs -V`)**
**JavaScript input** **JavaScript input**
@@ -24,6 +20,6 @@
**JavaScript output or error produced.** **JavaScript output or error produced.**
<!-- <!--
Note: `uglify-js` only supports ES5. Note: `uglify-js` only supports JavaScript.
Those wishing to minify ES6 should use `uglify-es`. Those wishing to minify ES6+ should transpile first.
--> -->

43
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: CI
on: [ push, pull_request ]
jobs:
test:
strategy:
matrix:
node: [ "0.8", "0.10", "0.12", "4", "6", "8", "10", "12", latest ]
os: [ ubuntu-latest, windows-latest ]
script: [ compress, mocha, release/benchmark, release/jetstream ]
exclude:
- node: "0.8"
script: release/jetstream
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
runs-on: ${{ matrix.os }}
env:
NODE: ${{ matrix.node }}
TYPE: ${{ matrix.script }}
steps:
- uses: actions/checkout@v1
- uses: actions/cache@v1
with:
path: tmp
key: tmp ${{ matrix.script }}
- name: Perform tests
shell: bash
run: |
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
cd ~/.nvs
git clean -xdf
cd -
done
. ~/.nvs/nvs.sh --version
nvs use $NODE
node --version
npm config set audit false
npm config set optional false
npm config set save false
npm config set strict-ssl false
npm config set update-notifier false
npm --version
while !(npm install); do echo "'npm install' failed - retrying..."; done
node test/$TYPE

34
.github/workflows/ufuzz.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Fuzzing
on:
schedule:
- cron: "*/15 * * * *"
jobs:
ufuzz:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
name: ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Perform fuzzing
shell: bash
run: |
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 10 && nvs use 10'; do
cd ~/.nvs
git clean -xdf
cd -
done
. ~/.nvs/nvs.sh --version
nvs use 10
node --version
npm config set audit false
npm config set optional false
npm config set save false
npm config set strict-ssl false
npm config set update-notifier false
npm --version
while !(npm install); do echo "'npm install' failed - retrying..."; done
node test/ufuzz/job 3600000

View File

@@ -1,14 +0,0 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "4"
- "6"
- "8"
env:
- UGLIFYJS_TEST_ALL=1
matrix:
fast_finish: true
sudo: false
cache:
directories: tmp

View File

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

View File

@@ -87,6 +87,7 @@ a double dash to prevent input files being used as option arguments:
`wrap_iife` Wrap IIFEs in parenthesis. Note: you may `wrap_iife` Wrap IIFEs in parenthesis. Note: you may
want to disable `negate_iife` under want to disable `negate_iife` under
compressor options. compressor options.
-O, --output-opts [options] Specify output options (`beautify` disabled by default).
-o, --output <file> Output file path (default STDOUT). Specify `ast` or -o, --output <file> Output file path (default STDOUT). Specify `ast` or
`spidermonkey` to write UglifyJS or SpiderMonkey AST `spidermonkey` to write UglifyJS or SpiderMonkey AST
as JSON to STDOUT respectively. as JSON to STDOUT respectively.
@@ -104,6 +105,8 @@ a double dash to prevent input files being used as option arguments:
sequences. sequences.
--config-file <file> Read `minify()` options from JSON file. --config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions. -d, --define <expr>[=value] Global definitions.
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
argument(s) & value(s).
--ie8 Support non-standard Internet Explorer 8. --ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()` Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options. for `compress`, `mangle` and `output` options.
@@ -118,7 +121,8 @@ a double dash to prevent input files being used as option arguments:
JS that was generated from some other original JS that was generated from some other original
code. Specify "inline" if the source map is code. Specify "inline" if the source map is
included within the sources. included within the sources.
`filename` Name and/or location of the output source. `filename` Filename and/or location of the output source
(sets `file` attribute in source map).
`includeSources` Pass this flag if you want to include `includeSources` Pass this flag if you want to include
the content of source files in the the content of source files in the
source map as sourcesContent property. source map as sourcesContent property.
@@ -149,7 +153,9 @@ debugging your compressed JavaScript. To get a source map, pass
Additional options: Additional options:
- `--source-map "filename='<NAME>'"` to specify the name of the source map. - `--source-map "filename='<NAME>'"` to specify the name of the source map. The value of
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
in source map file.
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found. - `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
@@ -473,42 +479,42 @@ if (result.error) throw result.error;
## Minify options ## Minify options
- `warnings` (default `false`) — pass `true` to return compressor warnings
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
- `parse` (default `{}`) — pass an object if you wish to specify some
additional [parse options](#parse-options).
- `compress` (default `{}`) — pass `false` to skip compressing entirely. - `compress` (default `{}`) — pass `false` to skip compressing entirely.
Pass an object to specify custom [compress options](#compress-options). Pass an object to specify custom [compress options](#compress-options).
- `ie8` (default `false`) -- set to `true` to support IE8.
- `keep_fnames` (default: `false`) -- pass `true` to prevent discarding or mangling
of function names. Useful for code relying on `Function.prototype.name`.
- `mangle` (default `true`) — pass `false` to skip mangling names, or pass - `mangle` (default `true`) — pass `false` to skip mangling names, or pass
an object to specify [mangle options](#mangle-options) (see below). an object to specify [mangle options](#mangle-options) (see below).
- `mangle.properties` (default `false`) — a subcategory of the mangle option. - `mangle.properties` (default `false`) — a subcategory of the mangle option.
Pass an object to specify custom [mangle property options](#mangle-properties-options). Pass an object to specify custom [mangle property options](#mangle-properties-options).
- `output` (default `null`) pass an object if you wish to specify - `nameCache` (default `null`) -- pass an empty object `{}` or a previously
additional [output options](#output-options). The defaults are optimized
for best compression.
- `sourceMap` (default `false`) - pass an object if you wish to specify
[source map options](#source-map-options).
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
variable and function name mangling and to drop unused variables and functions.
- `nameCache` (default `null`) - pass an empty object `{}` or a previously
used `nameCache` object if you wish to cache mangled variable and used `nameCache` object if you wish to cache mangled variable and
property names across multiple invocations of `minify()`. Note: this is property names across multiple invocations of `minify()`. Note: this is
a read/write property. `minify()` will read the name cache state of this a read/write property. `minify()` will read the name cache state of this
object and update it during minification so that it may be object and update it during minification so that it may be
reused or externally persisted by the user. reused or externally persisted by the user.
- `ie8` (default `false`) - set to `true` to support IE8. - `output` (default `null`) — pass an object if you wish to specify
additional [output options](#output-options). The defaults are optimized
for best compression.
- `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling - `parse` (default `{}`) pass an object if you wish to specify some
of function names. Useful for code relying on `Function.prototype.name`. additional [parse options](#parse-options).
- `sourceMap` (default `false`) -- pass an object if you wish to specify
[source map options](#source-map-options).
- `toplevel` (default `false`) -- set to `true` if you wish to enable top level
variable and function name mangling and to drop unused variables and functions.
- `warnings` (default `false`) — pass `true` to return compressor warnings
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
## Minify options structure ## Minify options structure
@@ -600,6 +606,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `arguments` (default: `true`) -- replace `arguments[index]` with function - `arguments` (default: `true`) -- replace `arguments[index]` with function
parameter name whenever possible. parameter name whenever possible.
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
- `booleans` (default: `true`) -- various optimizations for boolean context, - `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c` for example `!!a ? b : c → a ? b : c`
@@ -615,6 +623,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `dead_code` (default: `true`) -- remove unreachable code - `dead_code` (default: `true`) -- remove unreachable code
- `directives` (default: `true`) -- remove redundant or non-standard directives
- `drop_console` (default: `false`) -- Pass `true` to discard calls to - `drop_console` (default: `false`) -- Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call `console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments such as `console.info` and/or retain side effects from function arguments
@@ -622,11 +632,17 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `drop_debugger` (default: `true`) -- remove `debugger;` statements - `drop_debugger` (default: `true`) -- remove `debugger;` statements
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions - `evaluate` (default: `true`) -- Evaluate expression for shorter constant
representation. Pass `"eager"` to always replace function calls whenever
possible, or a positive integer to specify an upper bound for each individual
evaluation in number of characters.
- `expression` (default: `false`) -- Pass `true` to preserve completion values - `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets. from terminal statements without `return`, e.g. in bookmarklets.
- `functions` (default: `true`) -- convert declarations from `var`to `function`
whenever possible.
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation) - `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_funs` (default: `false`) -- hoist function declarations - `hoist_funs` (default: `false`) -- hoist function declarations
@@ -652,12 +668,13 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `join_vars` (default: `true`) -- join consecutive `var` statements - `join_vars` (default: `true`) -- join consecutive `var` statements
- `keep_fargs` (default: `true`) -- Prevents the compressor from discarding unused - `keep_fargs` (default: `strict`) -- Discard unused function arguments. Code
function arguments. You need this for code which relies on `Function.length`. which relies on `Function.length` will break if this is done indiscriminately,
i.e. when passing `true`. Pass `false` to always retain function arguments.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the - `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle). `Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle-options).
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from - `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome. being compressed into `1/0`, which may cause performance issues on Chrome.
@@ -669,6 +686,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
where the return value is discarded, to avoid the parens that the where the return value is discarded, to avoid the parens that the
code generator would insert. code generator would insert.
- `objects` (default: `true`) -- compact duplicate keys in object literals.
- `passes` (default: `1`) -- The maximum number of times to run compress. - `passes` (default: `1`) -- The maximum number of times to run compress.
In some cases more than one pass leads to further compressed code. Keep in In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time. mind more passes will take more time.
@@ -685,7 +704,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
function won't produce any side effect, in which case the whole function won't produce any side effect, in which case the whole
statement would get discarded. The current implementation adds some statement would get discarded. The current implementation adds some
overhead (compression will be slower). overhead (compression will be slower). Make sure symbols under `pure_funcs`
are also under `mangle.reserved` to avoid mangling.
- `pure_getters` (default: `"strict"`) -- If you pass `true` for - `pure_getters` (default: `"strict"`) -- If you pass `true` for
this, UglifyJS will assume that object property access this, UglifyJS will assume that object property access
@@ -716,6 +736,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();` example: `/*@__PURE__*/foo();`
- `strings` (default: `true`) -- compact string concatenations.
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches - `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or - `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
@@ -754,9 +776,6 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple - `unused` (default: `true`) -- drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`) direct variable assignments do not count as references unless set to `"keep_assign"`)
- `warnings` (default: `false`) -- display warnings when dropping unreachable
code or unused declarations etc.
## Mangle options ## Mangle options
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes - `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
@@ -829,8 +848,14 @@ can pass additional arguments that control the code output:
statement. statement.
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all - `comments` (default `false`) -- pass `true` or `"all"` to preserve all
comments, `"some"` to preserve some comments, a regular expression string comments, `"some"` to preserve multi-line comments that contain `@cc_on`,
(e.g. `/^!/`) or a function. `@license`, or `@preserve` (case-insensitive), a regular expression string
(e.g. `/^!/`), or a function which returns `boolean`, e.g.
```js
function(node, comment) {
return comment.value.indexOf("@type " + node.TYPE) >= 0;
}
```
- `indent_level` (default `4`) - `indent_level` (default `4`)
@@ -849,8 +874,8 @@ can pass additional arguments that control the code output:
adjust for this text. Can be used to insert a comment containing adjust for this text. Can be used to insert a comment containing
licensing information, for example. licensing information, for example.
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it - `preserve_line` (default `false`) -- pass `true` to retain line numbering on
only works if `beautify` is set to `false`. a best effort basis.
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal - `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
objects objects
@@ -1040,8 +1065,9 @@ var result = UglifyJS.minify(ast, {
### Working with Uglify AST ### Working with Uglify AST
Transversal and transformation of the native AST can be performed through Transversal and transformation of the native AST can be performed through
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and [`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively. [`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
respectively.
### ESTree / SpiderMonkey AST ### ESTree / SpiderMonkey AST

View File

@@ -1,20 +1,5 @@
environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4"
- nodejs_version: "6"
- nodejs_version: "8"
install:
- ps: Install-Product node $env:nodejs_version
- set UGLIFYJS_TEST_ALL=1
- npm install
build: off build: off
cache:
- tmp
matrix: matrix:
fast_finish: true fast_finish: true
test_script: test_script:
- node --version - echo No longer in use
- npm --version
- npm test

View File

@@ -36,10 +36,12 @@ program.option("-c, --compress [options]", "Enable compressor/specify compressor
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js()); program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js()); program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js()); program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
program.option("-O, --output-opts [options]", "Output options (beautify disabled).", parse_js());
program.option("-o, --output <file>", "Output file (default STDOUT)."); program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output."); program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file."); program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define")); program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
program.option("--ie8", "Support non-standard Internet Explorer 8."); program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name."); program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings."); program.option("--name-cache <file>", "File to hold mangled name mappings.");
@@ -47,20 +49,27 @@ program.option("--rename", "Force symbol expansion.");
program.option("--no-rename", "Disable symbol expansion."); program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)"); program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js()); program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
program.option("--timings", "Display operations run time on STDERR.") program.option("--timings", "Display operations run time on STDERR.");
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope."); program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages."); program.option("--verbose", "Print diagnostic messages.");
program.option("--warn", "Print warning messages."); program.option("--warn", "Print warning messages.");
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally."); program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
program.option("--reduce-test", "Reduce a standalone `console.log` based test case.");
program.arguments("[files...]").parseArgv(process.argv); program.arguments("[files...]").parseArgv(process.argv);
if (program.configFile) { if (program.configFile) {
options = JSON.parse(read_file(program.configFile)); options = JSON.parse(read_file(program.configFile));
if (options.mangle && options.mangle.properties && options.mangle.properties.regex) {
options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, {
expression: true
}).value;
}
} }
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") { if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
fatal("ERROR: cannot write source map to STDOUT"); fatal("cannot write source map to STDOUT");
} }
[ [
"compress", "compress",
"enclose",
"ie8", "ie8",
"mangle", "mangle",
"sourceMap", "sourceMap",
@@ -71,12 +80,25 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
options[name] = program[name]; options[name] = program[name];
} }
}); });
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (options.warnings) {
UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
delete options.warnings;
}
if (program.beautify) { if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {}; options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) { if (!("beautify" in options.output)) {
options.output.beautify = true; options.output.beautify = true;
} }
} }
if (program.outputOpts) {
if (program.beautify) fatal("--beautify cannot be used with --output-opts");
options.output = typeof program.outputOpts == "object" ? program.outputOpts : {};
}
if (program.comments) { if (program.comments) {
if (typeof options.output != "object") options.output = {}; if (typeof options.output != "object") options.output = {};
options.output.comments = typeof program.comments == "string" ? program.comments : "some"; options.output.comments = typeof program.comments == "string" ? program.comments : "some";
@@ -98,7 +120,7 @@ if (program.mangleProps) {
if (typeof program.mangleProps != "object") program.mangleProps = {}; if (typeof program.mangleProps != "object") program.mangleProps = {};
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = []; if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
require("../tools/domprops").forEach(function(name) { require("../tools/domprops").forEach(function(name) {
UglifyJS._push_uniq(program.mangleProps.reserved, name); UglifyJS.push_uniq(program.mangleProps.reserved, name);
}); });
} }
if (typeof options.mangle != "object") options.mangle = {}; if (typeof options.mangle != "object") options.mangle = {};
@@ -117,7 +139,7 @@ if (program.parse) {
if (!program.parse.acorn && !program.parse.spidermonkey) { if (!program.parse.acorn && !program.parse.spidermonkey) {
options.parse = program.parse; options.parse = program.parse;
} else if (program.sourceMap && program.sourceMap.content == "inline") { } else if (program.sourceMap && program.sourceMap.content == "inline") {
fatal("ERROR: inline source map only works with built-in parser"); fatal("inline source map only works with built-in parser");
} }
} }
if (~program.rawArgs.indexOf("--rename")) { if (~program.rawArgs.indexOf("--rename")) {
@@ -137,15 +159,8 @@ if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
}; };
}(); }();
} }
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (program.self) { if (program.self) {
if (program.args.length) { if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
print_error("WARN: Ignoring input files since --self was passed");
}
if (!options.wrap) options.wrap = "UglifyJS"; if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) { simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name); files[convert_path(name)] = read_file(name);
@@ -173,12 +188,9 @@ function convert_ast(fn) {
} }
function run() { function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
print_error("WARN: " + msg);
};
var content = program.sourceMap && program.sourceMap.content; var content = program.sourceMap && program.sourceMap.content;
if (content && content != "inline") { if (content && content != "inline") {
print_error("INFO: Using input source map: " + content); UglifyJS.AST_Node.info("Using input source map: " + content);
options.sourceMap.content = read_file(content, content); options.sourceMap.content = read_file(content, content);
} }
if (program.timings) options.timings = true; if (program.timings) options.timings = true;
@@ -204,13 +216,23 @@ function run() {
} catch (ex) { } catch (ex) {
fatal(ex); fatal(ex);
} }
if (program.reduceTest) {
// load on demand - assumes dev tree checked out
var reduce_test = require("../test/reduce");
var testcase = files[0] || files[Object.keys(files)[0]];
var result = reduce_test(testcase, options, {verbose: true});
}
else {
var result = UglifyJS.minify(files, options); var result = UglifyJS.minify(files, options);
}
if (result.error) { if (result.error) {
var ex = result.error; var ex = result.error;
if (ex.name == "SyntaxError") { if (ex.name == "SyntaxError") {
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col); print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
var file = files[ex.filename];
if (file) {
var col = ex.col; var col = ex.col;
var lines = files[ex.filename].split(/\r?\n/); var lines = file.split(/\r?\n/);
var line = lines[ex.line - 1]; var line = lines[ex.line - 1];
if (!line && !col) { if (!line && !col) {
line = lines[ex.line - 2]; line = lines[ex.line - 2];
@@ -226,7 +248,7 @@ function run() {
print_error(line.slice(0, col).replace(/\S/g, " ") + "^"); print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} }
} }
if (ex.defs) { } else if (ex.defs) {
print_error("Supported options:"); print_error("Supported options:");
print_error(format_object(ex.defs)); print_error(format_object(ex.defs));
} }
@@ -286,7 +308,11 @@ function run() {
} }
function fatal(message) { function fatal(message) {
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:") if (message instanceof Error) {
message = message.stack.replace(/^\S*?Error:/, "ERROR:")
} else {
message = "ERROR: " + message;
}
print_error(message); print_error(message);
process.exit(1); process.exit(1);
} }
@@ -311,7 +337,7 @@ function simple_glob(glob) {
.replace(/\?/g, "[^/\\\\]") + "$"; .replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : ""; var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod); var rx = new RegExp(pattern, mod);
var results = entries.filter(function(name) { var results = entries.sort().filter(function(name) {
return rx.test(name); return rx.test(name);
}).map(function(name) { }).map(function(name) {
return path.join(dir, name); return path.join(dir, name);
@@ -335,17 +361,9 @@ function parse_js(flag) {
return function(value, options) { return function(value, options) {
options = options || {}; options = options || {};
try { try {
UglifyJS.minify(value, { UglifyJS.parse(value, {
parse: {
expression: true expression: true
}, }).walk(new UglifyJS.TreeWalker(function(node) {
compress: false,
mangle: false,
output: {
ast: true,
code: false
}
}).ast.walk(new UglifyJS.TreeWalker(function(node) {
if (node instanceof UglifyJS.AST_Assign) { if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string(); var name = node.left.print_to_string();
var value = node.right; var value = node.right;
@@ -366,14 +384,14 @@ function parse_js(flag) {
if (!(node instanceof UglifyJS.AST_Sequence)) throw node; if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
function to_string(value) { function to_string(value) {
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({ return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
quote_keys: true quote_keys: true
}); });
} }
})); }));
} catch(ex) { } catch (ex) {
if (flag) { if (flag) {
fatal("Error parsing arguments for '" + flag + "': " + value); fatal("cannot parse arguments for '" + flag + "': " + value);
} else { } else {
options[value] = null; options[value] = null;
} }

View File

@@ -44,21 +44,21 @@
"use strict"; "use strict";
function DEFNODE(type, props, methods, base) { function DEFNODE(type, props, methods, base) {
if (arguments.length < 4) base = AST_Node; if (typeof base === "undefined") base = AST_Node;
if (!props) props = []; props = props ? props.split(/\s+/) : [];
else props = props.split(/\s+/);
var self_props = props; var self_props = props;
if (base && base.PROPS) if (base && base.PROPS) props = props.concat(base.PROPS);
props = props.concat(base.PROPS); var code = [
var code = "return function AST_" + type + "(props){ if (props) { "; "return function AST_", type, "(props){",
for (var i = props.length; --i >= 0;) { "if(props){",
code += "this." + props[i] + " = props." + props[i] + ";"; ];
} props.forEach(function(prop) {
code.push("this.", prop, "=props.", prop, ";");
});
var proto = base && new base; var proto = base && new base;
if (proto && proto.initialize || (methods && methods.initialize)) if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();");
code += "this.initialize();"; code.push("}}");
code += "}}"; var ctor = new Function(code.join(""))();
var ctor = new Function(code)();
if (proto) { if (proto) {
ctor.prototype = proto; ctor.prototype = proto;
ctor.BASE = base; ctor.BASE = base;
@@ -71,11 +71,11 @@ function DEFNODE(type, props, methods, base) {
if (type) { if (type) {
ctor.prototype.TYPE = ctor.TYPE = type; ctor.prototype.TYPE = ctor.TYPE = type;
} }
if (methods) for (i in methods) if (HOP(methods, i)) { if (methods) for (var name in methods) if (HOP(methods, name)) {
if (/^\$/.test(i)) { if (/^\$/.test(name)) {
ctor[i.substr(1)] = methods[i]; ctor[name.substr(1)] = methods[name];
} else { } else {
ctor.prototype[i] = methods[i]; ctor.prototype[name] = methods[name];
} }
} }
ctor.DEFMETHOD = function(name, method) { ctor.DEFMETHOD = function(name, method) {
@@ -85,7 +85,7 @@ function DEFNODE(type, props, methods, base) {
exports["AST_" + type] = ctor; exports["AST_" + type] = ctor;
} }
return ctor; return ctor;
}; }
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", { var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", {
}, null); }, null);
@@ -118,11 +118,25 @@ var AST_Node = DEFNODE("Node", "start end", {
} }
}, null); }, null);
AST_Node.warn_function = null; (AST_Node.log_function = function(fn, verbose) {
AST_Node.warn = function(txt, props) { var printed = Object.create(null);
if (AST_Node.warn_function) if (fn) {
AST_Node.warn_function(string_template(txt, props)); AST_Node.info = verbose ? function(text, props) {
}; log("INFO: " + string_template(text, props));
} : noop;
AST_Node.warn = function(text, props) {
log("WARN: " + string_template(text, props));
};
} else {
AST_Node.info = AST_Node.warn = noop;
}
function log(msg) {
if (printed[msg]) return;
printed[msg] = true;
fn(msg);
}
})();
/* -----[ statements ]----- */ /* -----[ statements ]----- */
@@ -148,21 +162,17 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.body._walk(visitor); this.body._walk(visitor);
}); });
} }
}, AST_Statement); }, AST_Statement);
function walk_body(node, visitor) { function walk_body(node, visitor) {
var body = node.body; node.body.forEach(function(node) {
if (body instanceof AST_Statement) { node._walk(visitor);
body._walk(visitor); });
} }
else for (var i = 0, len = body.length; i < len; i++) {
body[i]._walk(visitor);
}
};
var AST_Block = DEFNODE("Block", "body", { var AST_Block = DEFNODE("Block", "body", {
$documentation: "A body of statements (usually braced)", $documentation: "A body of statements (usually braced)",
@@ -170,7 +180,7 @@ var AST_Block = DEFNODE("Block", "body", {
body: "[AST_Statement*] an array of statements" body: "[AST_Statement*] an array of statements"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
walk_body(this, visitor); walk_body(this, visitor);
}); });
} }
@@ -197,7 +207,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
label: "[AST_Label] a label definition" label: "[AST_Label] a label definition"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.label._walk(visitor); this.label._walk(visitor);
this.body._walk(visitor); this.body._walk(visitor);
}); });
@@ -208,8 +218,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
var label = node.label; var label = node.label;
var def = this.label; var def = this.label;
node.walk(new TreeWalker(function(node) { node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
&& node.label && node.label.thedef === def) {
node.label.thedef = label; node.label.thedef = label;
label.references.push(node); label.references.push(node);
} }
@@ -233,7 +242,7 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
var AST_Do = DEFNODE("Do", null, { var AST_Do = DEFNODE("Do", null, {
$documentation: "A `do` statement", $documentation: "A `do` statement",
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.body._walk(visitor); this.body._walk(visitor);
this.condition._walk(visitor); this.condition._walk(visitor);
}); });
@@ -243,7 +252,7 @@ var AST_Do = DEFNODE("Do", null, {
var AST_While = DEFNODE("While", null, { var AST_While = DEFNODE("While", null, {
$documentation: "A `while` statement", $documentation: "A `while` statement",
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.condition._walk(visitor); this.condition._walk(visitor);
this.body._walk(visitor); this.body._walk(visitor);
}); });
@@ -258,7 +267,7 @@ var AST_For = DEFNODE("For", "init condition step", {
step: "[AST_Node?] the `for` update clause, or null if empty" step: "[AST_Node?] the `for` update clause, or null if empty"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
if (this.init) this.init._walk(visitor); if (this.init) this.init._walk(visitor);
if (this.condition) this.condition._walk(visitor); if (this.condition) this.condition._walk(visitor);
if (this.step) this.step._walk(visitor); if (this.step) this.step._walk(visitor);
@@ -274,7 +283,7 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
object: "[AST_Node] the object that we're looping through" object: "[AST_Node] the object that we're looping through"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.init._walk(visitor); this.init._walk(visitor);
this.object._walk(visitor); this.object._walk(visitor);
this.body._walk(visitor); this.body._walk(visitor);
@@ -288,7 +297,7 @@ var AST_With = DEFNODE("With", "expression", {
expression: "[AST_Node] the `with` expression" expression: "[AST_Node] the `with` expression"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
this.body._walk(visitor); this.body._walk(visitor);
}); });
@@ -314,6 +323,9 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
if (this.functions) node.functions = this.functions.clone(); if (this.functions) node.functions = this.functions.clone();
if (this.enclosed) node.enclosed = this.enclosed.slice(); if (this.enclosed) node.enclosed = this.enclosed.slice();
return node; return node;
},
pinned: function() {
return this.uses_eval || this.uses_with;
} }
}, AST_Block); }, AST_Block);
@@ -322,20 +334,46 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$propdoc: { $propdoc: {
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
}, },
wrap_commonjs: function(name) { wrap: function(name) {
var body = this.body; var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; return parse([
wrapped_tl = parse(wrapped_tl); "(function(exports){'$ORIG';})(typeof ",
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ name,
"=='undefined'?(",
name,
"={}):",
name,
");"
].join(""), {
filename: "wrap=" + JSON.stringify(name)
}).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") { if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body); return List.splice(body);
}
}));
},
enclose: function(args_values) {
if (typeof args_values != "string") args_values = "";
var index = args_values.indexOf(":");
if (index < 0) index = args_values.length;
var body = this.body;
return parse([
"(function(",
args_values.slice(0, index),
'){"$ORIG"})(',
args_values.slice(index + 1),
")"
].join(""), {
filename: "enclose=" + JSON.stringify(args_values)
}).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return List.splice(body);
} }
})); }));
return wrapped_tl;
} }
}, AST_Scope); }, AST_Scope);
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
$documentation: "Base class for functions", $documentation: "Base class for functions",
$propdoc: { $propdoc: {
name: "[AST_SymbolDeclaration?] the name of this function", name: "[AST_SymbolDeclaration?] the name of this function",
@@ -343,12 +381,11 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
if (this.name) this.name._walk(visitor); if (this.name) this.name._walk(visitor);
var argnames = this.argnames; this.argnames.forEach(function(argname) {
for (var i = 0, len = argnames.length; i < len; i++) { argname._walk(visitor);
argnames[i]._walk(visitor); });
}
walk_body(this, visitor); walk_body(this, visitor);
}); });
} }
@@ -378,7 +415,7 @@ var AST_Exit = DEFNODE("Exit", "value", {
value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, this.value && function(){ return visitor._visit(this, this.value && function() {
this.value._walk(visitor); this.value._walk(visitor);
}); });
} }
@@ -398,7 +435,7 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
label: "[AST_LabelRef?] the label, or null if none", label: "[AST_LabelRef?] the label, or null if none",
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, this.label && function(){ return visitor._visit(this, this.label && function() {
this.label._walk(visitor); this.label._walk(visitor);
}); });
} }
@@ -421,7 +458,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
alternative: "[AST_Statement?] the `else` part, or null if not present" alternative: "[AST_Statement?] the `else` part, or null if not present"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.condition._walk(visitor); this.condition._walk(visitor);
this.body._walk(visitor); this.body._walk(visitor);
if (this.alternative) this.alternative._walk(visitor); if (this.alternative) this.alternative._walk(visitor);
@@ -437,7 +474,7 @@ var AST_Switch = DEFNODE("Switch", "expression", {
expression: "[AST_Node] the `switch` “discriminant”" expression: "[AST_Node] the `switch` “discriminant”"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
walk_body(this, visitor); walk_body(this, visitor);
}); });
@@ -458,7 +495,7 @@ var AST_Case = DEFNODE("Case", "expression", {
expression: "[AST_Node] the `case` expression" expression: "[AST_Node] the `case` expression"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
walk_body(this, visitor); walk_body(this, visitor);
}); });
@@ -474,7 +511,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
bfinally: "[AST_Finally?] the finally block, or null if not present" bfinally: "[AST_Finally?] the finally block, or null if not present"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
walk_body(this, visitor); walk_body(this, visitor);
if (this.bcatch) this.bcatch._walk(visitor); if (this.bcatch) this.bcatch._walk(visitor);
if (this.bfinally) this.bfinally._walk(visitor); if (this.bfinally) this.bfinally._walk(visitor);
@@ -488,7 +525,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
argname: "[AST_SymbolCatch] symbol for the exception" argname: "[AST_SymbolCatch] symbol for the exception"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.argname._walk(visitor); this.argname._walk(visitor);
walk_body(this, visitor); walk_body(this, visitor);
}); });
@@ -507,11 +544,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
definitions: "[AST_VarDef*] array of variable definitions" definitions: "[AST_VarDef*] array of variable definitions"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
var definitions = this.definitions; this.definitions.forEach(function(defn) {
for (var i = 0, len = definitions.length; i < len; i++) { defn._walk(visitor);
definitions[i]._walk(visitor); });
}
}); });
} }
}, AST_Statement); }, AST_Statement);
@@ -527,7 +563,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
value: "[AST_Node?] initializer, or null of there's no initializer" value: "[AST_Node?] initializer, or null of there's no initializer"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.name._walk(visitor); this.name._walk(visitor);
if (this.value) this.value._walk(visitor); if (this.value) this.value._walk(visitor);
}); });
@@ -543,12 +579,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
args: "[AST_Node*] array of arguments" args: "[AST_Node*] array of arguments"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
this.expression._walk(visitor); this.expression._walk(visitor);
this.args.forEach(function(node) {
node._walk(visitor);
});
}); });
} }
}); });
@@ -563,7 +598,7 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
expressions: "[AST_Node*] array of expressions (at least two)" expressions: "[AST_Node*] array of expressions (at least two)"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expressions.forEach(function(node) { this.expressions.forEach(function(node) {
node._walk(visitor); node._walk(visitor);
}); });
@@ -576,13 +611,25 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
$propdoc: { $propdoc: {
expression: "[AST_Node] the “container” expression", expression: "[AST_Node] the “container” expression",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
},
getProperty: function() {
var p = this.property;
if (p instanceof AST_Constant) {
return p.value;
}
if (p instanceof AST_UnaryPrefix
&& p.operator == "void"
&& p.expression instanceof AST_Constant) {
return;
}
return p;
} }
}); });
var AST_Dot = DEFNODE("Dot", null, { var AST_Dot = DEFNODE("Dot", null, {
$documentation: "A dotted property access expression", $documentation: "A dotted property access expression",
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
}); });
} }
@@ -591,7 +638,7 @@ var AST_Dot = DEFNODE("Dot", null, {
var AST_Sub = DEFNODE("Sub", null, { var AST_Sub = DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`", $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
this.property._walk(visitor); this.property._walk(visitor);
}); });
@@ -605,7 +652,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
expression: "[AST_Node] expression that this unary operator applies to" expression: "[AST_Node] expression that this unary operator applies to"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.expression._walk(visitor); this.expression._walk(visitor);
}); });
} }
@@ -627,7 +674,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
right: "[AST_Node] right-hand side expression" right: "[AST_Node] right-hand side expression"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.left._walk(visitor); this.left._walk(visitor);
this.right._walk(visitor); this.right._walk(visitor);
}); });
@@ -642,7 +689,7 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
alternative: "[AST_Node]" alternative: "[AST_Node]"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.condition._walk(visitor); this.condition._walk(visitor);
this.consequent._walk(visitor); this.consequent._walk(visitor);
this.alternative._walk(visitor); this.alternative._walk(visitor);
@@ -662,11 +709,10 @@ var AST_Array = DEFNODE("Array", "elements", {
elements: "[AST_Node*] array of elements" elements: "[AST_Node*] array of elements"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
var elements = this.elements; this.elements.forEach(function(element) {
for (var i = 0, len = elements.length; i < len; i++) { element._walk(visitor);
elements[i]._walk(visitor); });
}
}); });
} }
}); });
@@ -677,11 +723,10 @@ var AST_Object = DEFNODE("Object", "properties", {
properties: "[AST_ObjectProperty*] array of properties" properties: "[AST_ObjectProperty*] array of properties"
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
var properties = this.properties; this.properties.forEach(function(prop) {
for (var i = 0, len = properties.length; i < len; i++) { prop._walk(visitor);
properties[i]._walk(visitor); });
}
}); });
} }
}); });
@@ -693,7 +738,7 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor." value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function() {
this.value._walk(visitor); this.value._walk(visitor);
}); });
} }
@@ -762,7 +807,7 @@ var AST_Label = DEFNODE("Label", "references", {
} }
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", null, { var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
$documentation: "Reference to some symbol (not definition/declaration)", $documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol); }, AST_Symbol);
@@ -776,9 +821,6 @@ var AST_This = DEFNODE("This", null, {
var AST_Constant = DEFNODE("Constant", null, { var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants", $documentation: "Base class for all constants",
getValue: function() {
return this.value;
}
}); });
var AST_String = DEFNODE("String", "value quote", { var AST_String = DEFNODE("String", "value quote", {
@@ -789,11 +831,10 @@ var AST_String = DEFNODE("String", "value quote", {
} }
}, AST_Constant); }, AST_Constant);
var AST_Number = DEFNODE("Number", "value literal", { var AST_Number = DEFNODE("Number", "value", {
$documentation: "A number literal", $documentation: "A number literal",
$propdoc: { $propdoc: {
value: "[number] the numeric value", value: "[number] the numeric value",
literal: "[string] numeric value as string (optional)"
} }
}, AST_Constant); }, AST_Constant);
@@ -820,12 +861,12 @@ var AST_NaN = DEFNODE("NaN", null, {
var AST_Undefined = DEFNODE("Undefined", null, { var AST_Undefined = DEFNODE("Undefined", null, {
$documentation: "The `undefined` value", $documentation: "The `undefined` value",
value: (function(){}()) value: function(){}()
}, AST_Atom); }, AST_Atom);
var AST_Hole = DEFNODE("Hole", null, { var AST_Hole = DEFNODE("Hole", null, {
$documentation: "A hole in an array", $documentation: "A hole in an array",
value: (function(){}()) value: function(){}()
}, AST_Atom); }, AST_Atom);
var AST_Infinity = DEFNODE("Infinity", null, { var AST_Infinity = DEFNODE("Infinity", null, {
@@ -853,11 +894,11 @@ function TreeWalker(callback) {
this.visit = callback; this.visit = callback;
this.stack = []; this.stack = [];
this.directives = Object.create(null); this.directives = Object.create(null);
}; }
TreeWalker.prototype = { TreeWalker.prototype = {
_visit: function(node, descend) { _visit: function(node, descend) {
this.push(node); this.push(node);
var ret = this.visit(node, descend ? function(){ var ret = this.visit(node, descend ? function() {
descend.call(node); descend.call(node);
} : noop); } : noop);
if (!ret && descend) { if (!ret && descend) {
@@ -920,11 +961,13 @@ TreeWalker.prototype = {
in_boolean_context: function() { in_boolean_context: function() {
var self = this.self(); var self = this.self();
for (var i = 0, p; p = this.parent(i); i++) { for (var i = 0, p; p = this.parent(i); i++) {
if (p instanceof AST_SimpleStatement if (p instanceof AST_Conditional && p.condition === self
|| p instanceof AST_Conditional && p.condition === self
|| p instanceof AST_DWLoop && p.condition === self || p instanceof AST_DWLoop && p.condition === self
|| p instanceof AST_For && p.condition === self || p instanceof AST_For && p.condition === self
|| p instanceof AST_If && p.condition === self || p instanceof AST_If && p.condition === self
|| p instanceof AST_Return && p.in_bool
|| p instanceof AST_Sequence && p.tail_node() !== self
|| p instanceof AST_SimpleStatement
|| p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
return true; return true;
} }
@@ -932,6 +975,15 @@ TreeWalker.prototype = {
|| p instanceof AST_Conditional || p instanceof AST_Conditional
|| p.tail_node() === self) { || p.tail_node() === self) {
self = p; self = p;
} else if (p instanceof AST_Return) {
var fn;
do {
fn = this.parent(++i);
if (!fn) return false;
} while (!(fn instanceof AST_Lambda));
if (fn.name) return false;
self = this.parent(++i);
if (!self || self.TYPE != "Call" || self.expression !== fn) return false;
} else { } else {
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,39 @@
"use strict"; "use strict";
var to_ascii = typeof atob == "undefined" ? function(b64) { var to_ascii, to_base64;
if (typeof Buffer == "undefined") {
to_ascii = atob;
to_base64 = btoa;
} else if (typeof Buffer.alloc == "undefined") {
to_ascii = function(b64) {
return new Buffer(b64, "base64").toString(); return new Buffer(b64, "base64").toString();
} : atob; };
var to_base64 = typeof btoa == "undefined" ? function(str) { to_base64 = function(str) {
return new Buffer(str).toString("base64"); return new Buffer(str).toString("base64");
} : btoa; };
} else {
to_ascii = function(b64) {
return Buffer.from(b64, "base64").toString();
};
to_base64 = function(str) {
return Buffer.from(str).toString("base64");
};
}
function read_source_map(name, code) { function read_source_map(name, toplevel) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); var comments = toplevel.end.comments_after;
if (!match) { for (var i = comments.length; --i >= 0;) {
AST_Node.warn("inline source map not found: " + name); var comment = comments[i];
return null; if (comment.type != "comment1") break;
} var match = /^# ([^\s=]+)=(\S+)\s*$/.exec(comment.value);
if (!match) break;
if (match[1] == "sourceMappingURL") {
match = /^data:application\/json(;.*?)?;base64,(\S+)$/.exec(match[2]);
if (!match) break;
return to_ascii(match[2]); return to_ascii(match[2]);
}
}
AST_Node.warn("inline source map not found: " + name);
} }
function parse_source_map(content) { function parse_source_map(content) {
@@ -51,10 +71,10 @@ function to_json(cache) {
} }
function minify(files, options) { function minify(files, options) {
var warn_function = AST_Node.warn_function;
try { try {
options = defaults(options, { options = defaults(options, {
compress: {}, compress: {},
enclose: false,
ie8: false, ie8: false,
keep_fnames: false, keep_fnames: false,
mangle: {}, mangle: {},
@@ -77,7 +97,6 @@ function minify(files, options) {
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]); set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
var quoted_props; var quoted_props;
if (options.mangle) { if (options.mangle) {
options.mangle = defaults(options.mangle, { options.mangle = defaults(options.mangle, {
@@ -115,11 +134,9 @@ function minify(files, options) {
}, true); }, true);
} }
var warnings = []; var warnings = [];
if (options.warnings && !AST_Node.warn_function) { if (options.warnings) AST_Node.log_function(function(warning) {
AST_Node.warn_function = function(warning) {
warnings.push(warning); warnings.push(warning);
}; }, options.warnings == "verbose");
}
if (timings) timings.parse = Date.now(); if (timings) timings.parse = Date.now();
var source_maps, toplevel; var source_maps, toplevel;
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
@@ -137,10 +154,10 @@ function minify(files, options) {
source_maps = source_map_content && Object.create(null); source_maps = source_map_content && Object.create(null);
for (var name in files) if (HOP(files, name)) { for (var name in files) if (HOP(files, name)) {
options.parse.filename = name; options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse); options.parse.toplevel = toplevel = parse(files[name], options.parse);
if (source_maps) { if (source_maps) {
if (source_map_content == "inline") { if (source_map_content == "inline") {
var inlined_content = read_source_map(name, files[name]); var inlined_content = read_source_map(name, toplevel);
if (inlined_content) { if (inlined_content) {
source_maps[name] = parse_source_map(inlined_content); source_maps[name] = parse_source_map(inlined_content);
} }
@@ -149,14 +166,17 @@ function minify(files, options) {
} }
} }
} }
toplevel = options.parse.toplevel;
} }
if (quoted_props) { if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props); reserve_quoted_keys(toplevel, quoted_props);
} }
if (options.wrap) { [ "enclose", "wrap" ].forEach(function(action) {
toplevel = toplevel.wrap_commonjs(options.wrap); var option = options[action];
} if (!option) return;
var orig = toplevel.print_to_string().slice(0, -1);
toplevel = toplevel[action](option);
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
});
if (timings) timings.rename = Date.now(); if (timings) timings.rename = Date.now();
if (options.rename) { if (options.rename) {
toplevel.figure_out_scope(options.mangle); toplevel.figure_out_scope(options.mangle);
@@ -183,6 +203,7 @@ function minify(files, options) {
if (!HOP(options.output, "code") || options.output.code) { if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) { if (options.sourceMap) {
options.output.source_map = SourceMap({ options.output.source_map = SourceMap({
content: options.sourceMap.includeSources,
file: options.sourceMap.filename, file: options.sourceMap.filename,
orig: source_maps, orig: source_maps,
root: options.sourceMap.root root: options.sourceMap.root
@@ -191,10 +212,8 @@ function minify(files, options) {
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable"); throw new Error("original source content unavailable");
} else for (var name in files) if (HOP(files, name)) { } else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]); options.output.source_map.setSourceContent(name, files[name]);
} }
} else {
options.output.source_map.get()._sourcesContents = null;
} }
} }
delete options.output.ast; delete options.output.ast;
@@ -204,10 +223,14 @@ function minify(files, options) {
result.code = stream.get(); result.code = stream.get();
if (options.sourceMap) { if (options.sourceMap) {
result.map = options.output.source_map.toString(); result.map = options.output.source_map.toString();
if (options.sourceMap.url == "inline") { var url = options.sourceMap.url;
if (url) {
result.code = result.code.replace(/\n\/\/# sourceMappingURL=\S+\s*$/, "");
if (url == "inline") {
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map); result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map);
} else if (options.sourceMap.url) { } else {
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url; result.code += "\n//# sourceMappingURL=" + url;
}
} }
} }
} }
@@ -228,7 +251,7 @@ function minify(files, options) {
properties: 1e-3 * (timings.output - timings.properties), properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output), output: 1e-3 * (timings.end - timings.output),
total: 1e-3 * (timings.end - timings.start) total: 1e-3 * (timings.end - timings.start)
} };
} }
if (warnings.length) { if (warnings.length) {
result.warnings = warnings; result.warnings = warnings;
@@ -236,7 +259,5 @@ function minify(files, options) {
return result; return result;
} catch (ex) { } catch (ex) {
return { error: ex }; return { error: ex };
} finally {
AST_Node.warn_function = warn_function;
} }
} }

View File

@@ -43,11 +43,9 @@
"use strict"; "use strict";
(function(){ (function() {
function normalize_directives(body) {
var normalize_directives = function(body) {
var in_directive = true; var in_directive = true;
for (var i = 0; i < body.length; i++) { for (var i = 0; i < body.length; i++) {
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) { if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
body[i] = new AST_Directive({ body[i] = new AST_Directive({
@@ -59,9 +57,8 @@
in_directive = false; in_directive = false;
} }
} }
return body; return body;
}; }
var MOZ_TO_ME = { var MOZ_TO_ME = {
Program: function(M) { Program: function(M) {
@@ -129,7 +126,7 @@
return new AST_Array({ return new AST_Array({
start : my_start_token(M), start : my_start_token(M),
end : my_end_token(M), end : my_end_token(M),
elements : M.elements.map(function(elem){ elements : M.elements.map(function(elem) {
return elem === null ? new AST_Hole() : from_moz(elem); return elem === null ? new AST_Hole() : from_moz(elem);
}) })
}); });
@@ -138,7 +135,7 @@
return new AST_Object({ return new AST_Object({
start : my_start_token(M), start : my_start_token(M),
end : my_end_token(M), end : my_end_token(M),
properties : M.properties.map(function(prop){ properties : M.properties.map(function(prop) {
prop.type = "Property"; prop.type = "Property";
return from_moz(prop) return from_moz(prop)
}) })
@@ -406,7 +403,7 @@
var def = M.definition(); var def = M.definition();
return { return {
type: "Identifier", type: "Identifier",
name: def ? def.mangled_name || def.name : M.name name: def && def.mangled_name || M.name
}; };
}); });
@@ -480,7 +477,7 @@
endpos : range ? range[0] : moznode.start, endpos : range ? range[0] : moznode.start,
raw : raw_token(moznode), raw : raw_token(moznode),
}); });
}; }
function my_end_token(moznode) { function my_end_token(moznode) {
var loc = moznode.loc, end = loc && loc.end; var loc = moznode.loc, end = loc && loc.end;
@@ -495,7 +492,7 @@
endpos : range ? range[1] : moznode.end, endpos : range ? range[1] : moznode.end,
raw : raw_token(moznode), raw : raw_token(moznode),
}); });
}; }
function map(moztype, mytype, propmap) { function map(moztype, mytype, propmap) {
var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
@@ -507,7 +504,7 @@
me_to_moz += "return {\n" + me_to_moz += "return {\n" +
"type: " + JSON.stringify(moztype); "type: " + JSON.stringify(moztype);
if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
if (!m) throw new Error("Can't understand property map: " + prop); if (!m) throw new Error("Can't understand property map: " + prop);
var moz = m[1], how = m[2], my = m[3]; var moz = m[1], how = m[2], my = m[3];
@@ -550,7 +547,7 @@
); );
MOZ_TO_ME[moztype] = moz_to_me; MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz); def_to_moz(mytype, me_to_moz);
}; }
var FROM_MOZ_STACK = null; var FROM_MOZ_STACK = null;
@@ -559,9 +556,9 @@
var ret = node != null ? MOZ_TO_ME[node.type](node) : null; var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
FROM_MOZ_STACK.pop(); FROM_MOZ_STACK.pop();
return ret; return ret;
}; }
AST_Node.from_mozilla_ast = function(node){ AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK; var save_stack = FROM_MOZ_STACK;
FROM_MOZ_STACK = []; FROM_MOZ_STACK = [];
var ast = from_moz(node); var ast = from_moz(node);
@@ -600,24 +597,24 @@
} }
} }
return moznode; return moznode;
}; }
function def_to_moz(mytype, handler) { function def_to_moz(mytype, handler) {
mytype.DEFMETHOD("to_mozilla_ast", function() { mytype.DEFMETHOD("to_mozilla_ast", function() {
return set_moz_loc(this, handler(this)); return set_moz_loc(this, handler(this));
}); });
}; }
function to_moz(node) { function to_moz(node) {
return node != null ? node.to_mozilla_ast() : null; return node != null ? node.to_mozilla_ast() : null;
}; }
function to_moz_block(node) { function to_moz_block(node) {
return { return {
type: "BlockStatement", type: "BlockStatement",
body: node.body.map(to_moz) body: node.body.map(to_moz)
}; };
}; }
function to_moz_scope(type, node) { function to_moz_scope(type, node) {
var body = node.body.map(to_moz); var body = node.body.map(to_moz);
@@ -628,5 +625,5 @@
type: type, type: type,
body: body body: body
}; };
}; }
})(); })();

File diff suppressed because it is too large Load Diff

View File

@@ -130,27 +130,23 @@ function is_letter(code) {
return (code >= 97 && code <= 122) return (code >= 97 && code <= 122)
|| (code >= 65 && code <= 90) || (code >= 65 && code <= 90)
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code))); || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
}; }
function is_surrogate_pair_head(code) { function is_surrogate_pair_head(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xd800 && code <= 0xdbff; return code >= 0xd800 && code <= 0xdbff;
} }
function is_surrogate_pair_tail(code) { function is_surrogate_pair_tail(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xdc00 && code <= 0xdfff; return code >= 0xdc00 && code <= 0xdfff;
} }
function is_digit(code) { function is_digit(code) {
return code >= 48 && code <= 57; return code >= 48 && code <= 57;
}; }
function is_alphanumeric_char(code) { function is_alphanumeric_char(code) {
return is_digit(code) || is_letter(code); return is_digit(code) || is_letter(code);
}; }
function is_unicode_digit(code) { function is_unicode_digit(code) {
return UNICODE.digit.test(String.fromCharCode(code)); return UNICODE.digit.test(String.fromCharCode(code));
@@ -158,19 +154,15 @@ function is_unicode_digit(code) {
function is_unicode_combining_mark(ch) { function is_unicode_combining_mark(ch) {
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
}; }
function is_unicode_connector_punctuation(ch) { function is_unicode_connector_punctuation(ch) {
return UNICODE.connector_punctuation.test(ch); return UNICODE.connector_punctuation.test(ch);
}; }
function is_identifier(name) {
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
};
function is_identifier_start(code) { function is_identifier_start(code) {
return code == 36 || code == 95 || is_letter(code); return code == 36 || code == 95 || is_letter(code);
}; }
function is_identifier_char(ch) { function is_identifier_char(ch) {
var code = ch.charCodeAt(0); var code = ch.charCodeAt(0);
@@ -182,11 +174,11 @@ function is_identifier_char(ch) {
|| is_unicode_connector_punctuation(ch) || is_unicode_connector_punctuation(ch)
|| is_unicode_digit(code) || is_unicode_digit(code)
; ;
}; }
function is_identifier_string(str){ function is_identifier_string(str) {
return /^[a-z_$][a-z0-9_$]*$/i.test(str); return /^[a-z_$][a-z0-9_$]*$/i.test(str);
}; }
function parse_js_number(num) { function parse_js_number(num) {
if (RE_HEX_NUMBER.test(num)) { if (RE_HEX_NUMBER.test(num)) {
@@ -197,7 +189,7 @@ function parse_js_number(num) {
var val = parseFloat(num); var val = parseFloat(num);
if (val == num) return val; if (val == num) return val;
} }
}; }
function JS_Parse_Error(message, filename, line, col, pos) { function JS_Parse_Error(message, filename, line, col, pos) {
this.message = message; this.message = message;
@@ -205,7 +197,7 @@ function JS_Parse_Error(message, filename, line, col, pos) {
this.line = line; this.line = line;
this.col = col; this.col = col;
this.pos = pos; this.pos = pos;
}; }
JS_Parse_Error.prototype = Object.create(Error.prototype); JS_Parse_Error.prototype = Object.create(Error.prototype);
JS_Parse_Error.prototype.constructor = JS_Parse_Error; JS_Parse_Error.prototype.constructor = JS_Parse_Error;
JS_Parse_Error.prototype.name = "SyntaxError"; JS_Parse_Error.prototype.name = "SyntaxError";
@@ -213,11 +205,11 @@ configure_error_stack(JS_Parse_Error);
function js_error(message, filename, line, col, pos) { function js_error(message, filename, line, col, pos) {
throw new JS_Parse_Error(message, filename, line, col, pos); throw new JS_Parse_Error(message, filename, line, col, pos);
}; }
function is_token(token, type, val) { function is_token(token, type, val) {
return token.type == type && (val == null || token.value == val); return token.type == type && (val == null || token.value == val);
}; }
var EX_EOF = {}; var EX_EOF = {};
@@ -238,68 +230,65 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
directives : {}, directives : {},
directive_stack : [] directive_stack : []
}; };
var prev_was_dot = false;
function peek() { return S.text.charAt(S.pos); }; function peek() {
return S.text.charAt(S.pos);
}
function next(signal_eof, in_string) { function next(signal_eof, in_string) {
var ch = S.text.charAt(S.pos++); var ch = S.text.charAt(S.pos++);
if (signal_eof && !ch) if (signal_eof && !ch)
throw EX_EOF; throw EX_EOF;
if (NEWLINE_CHARS[ch]) { if (NEWLINE_CHARS[ch]) {
S.newline_before = S.newline_before || !in_string;
++S.line;
S.col = 0; S.col = 0;
if (!in_string && ch == "\r" && peek() == "\n") { S.line++;
// treat a \r\n sequence as a single \n if (!in_string) S.newline_before = true;
++S.pos; if (ch == "\r" && peek() == "\n") {
// treat `\r\n` as `\n`
S.pos++;
ch = "\n"; ch = "\n";
} }
} else { } else {
++S.col; S.col++;
} }
return ch; return ch;
}; }
function forward(i) { function forward(i) {
while (i-- > 0) next(); while (i-- > 0) next();
}; }
function looking_at(str) { function looking_at(str) {
return S.text.substr(S.pos, str.length) == str; return S.text.substr(S.pos, str.length) == str;
}; }
function find_eol() { function find_eol() {
var text = S.text; var text = S.text;
for (var i = S.pos, n = S.text.length; i < n; ++i) { for (var i = S.pos; i < S.text.length; ++i) {
var ch = text[i]; if (NEWLINE_CHARS[text[i]]) return i;
if (NEWLINE_CHARS[ch])
return i;
} }
return -1; return -1;
}; }
function find(what, signal_eof) { function find(what, signal_eof) {
var pos = S.text.indexOf(what, S.pos); var pos = S.text.indexOf(what, S.pos);
if (signal_eof && pos == -1) throw EX_EOF; if (signal_eof && pos == -1) throw EX_EOF;
return pos; return pos;
}; }
function start_token() { function start_token() {
S.tokline = S.line; S.tokline = S.line;
S.tokcol = S.col; S.tokcol = S.col;
S.tokpos = S.pos; S.tokpos = S.pos;
};
var prev_was_dot = false;
function token(type, value, is_comment) {
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX[value]) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION[value]));
if (type == "punc" && value == ".") {
prev_was_dot = true;
} else if (!is_comment) {
prev_was_dot = false;
} }
function token(type, value, is_comment) {
S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value]
|| type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]
|| type == "punc" && PUNC_BEFORE_EXPRESSION[value];
if (type == "punc" && value == ".") prev_was_dot = true;
else if (!is_comment) prev_was_dot = false;
var ret = { var ret = {
type : type, type : type,
value : value, value : value,
@@ -321,27 +310,27 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
S.newline_before = false; S.newline_before = false;
return new AST_Token(ret); return new AST_Token(ret);
}; }
function skip_whitespace() { function skip_whitespace() {
while (WHITESPACE_CHARS[peek()]) while (WHITESPACE_CHARS[peek()])
next(); next();
}; }
function read_while(pred) { function read_while(pred) {
var ret = "", ch, i = 0; var ret = "", ch, i = 0;
while ((ch = peek()) && pred(ch, i++)) while ((ch = peek()) && pred(ch, i++))
ret += next(); ret += next();
return ret; return ret;
}; }
function parse_error(err) { function parse_error(err) {
js_error(err, filename, S.tokline, S.tokcol, S.tokpos); js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
}; }
function read_num(prefix) { function read_num(prefix) {
var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
var num = read_while(function(ch, i){ var num = read_while(function(ch, i) {
var code = ch.charCodeAt(0); var code = ch.charCodeAt(0);
switch (code) { switch (code) {
case 120: case 88: // xX case 120: case 88: // xX
@@ -362,12 +351,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
parse_error("Legacy octal literals are not allowed in strict mode"); parse_error("Legacy octal literals are not allowed in strict mode");
} }
var valid = parse_js_number(num); var valid = parse_js_number(num);
if (!isNaN(valid)) { if (!isNaN(valid)) return token("num", valid);
return token("num", valid);
} else {
parse_error("Invalid syntax: " + num); parse_error("Invalid syntax: " + num);
} }
};
function read_escaped_char(in_string) { function read_escaped_char(in_string) {
var ch = next(true, in_string); var ch = next(true, in_string);
@@ -390,7 +376,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (ch >= "0" && ch <= "7") if (ch >= "0" && ch <= "7")
return read_octal_escape_sequence(ch); return read_octal_escape_sequence(ch);
return ch; return ch;
}; }
function read_octal_escape_sequence(ch) { function read_octal_escape_sequence(ch) {
// Read // Read
@@ -417,9 +403,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
num = (num << 4) | digit; num = (num << 4) | digit;
} }
return num; return num;
}; }
var read_string = with_eof_error("Unterminated string constant", function(quote_char){ var read_string = with_eof_error("Unterminated string constant", function(quote_char) {
var quote = next(), ret = ""; var quote = next(), ret = "";
for (;;) { for (;;) {
var ch = next(true, true); var ch = next(true, true);
@@ -447,9 +433,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
S.comments_before.push(token(type, ret, true)); S.comments_before.push(token(type, ret, true));
S.regex_allowed = regex_allowed; S.regex_allowed = regex_allowed;
return next_token; return next_token;
}; }
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){ var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
var regex_allowed = S.regex_allowed; var regex_allowed = S.regex_allowed;
var i = find("*/", true); var i = find("*/", true);
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n'); var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
@@ -467,8 +453,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (ch == "\\") escaped = backslash = true, next(); if (ch == "\\") escaped = backslash = true, next();
else if (is_identifier_char(ch)) name += next(); else if (is_identifier_char(ch)) name += next();
else break; else break;
} } else {
else {
if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
ch = read_escaped_char(); ch = read_escaped_char();
if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
@@ -481,7 +466,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
} }
return name; return name;
}; }
var read_regexp = with_eof_error("Unterminated regular expression", function(source) { var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
var prev_backslash = false, ch, in_class = false; var prev_backslash = false, ch, in_class = false;
@@ -508,7 +493,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var regexp = new RegExp(source, mods); var regexp = new RegExp(source, mods);
regexp.raw_source = source; regexp.raw_source = source;
return token("regexp", regexp); return token("regexp", regexp);
} catch(e) { } catch (e) {
parse_error(e.message); parse_error(e.message);
} }
}); });
@@ -523,9 +508,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} else { } else {
return op; return op;
} }
}; }
return token("operator", grow(prefix || next())); return token("operator", grow(prefix || next()));
}; }
function handle_slash() { function handle_slash() {
next(); next();
@@ -538,14 +523,12 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return skip_multiline_comment(); return skip_multiline_comment();
} }
return S.regex_allowed ? read_regexp("") : read_operator("/"); return S.regex_allowed ? read_regexp("") : read_operator("/");
}; }
function handle_dot() { function handle_dot() {
next(); next();
return is_digit(peek().charCodeAt(0)) return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
? read_num(".") }
: token("punc", ".");
};
function read_word() { function read_word() {
var word = read_name(); var word = read_name();
@@ -554,18 +537,18 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
: !KEYWORDS[word] ? token("name", word) : !KEYWORDS[word] ? token("name", word)
: OPERATORS[word] ? token("operator", word) : OPERATORS[word] ? token("operator", word)
: token("keyword", word); : token("keyword", word);
}; }
function with_eof_error(eof_error, cont) { function with_eof_error(eof_error, cont) {
return function(x) { return function(x) {
try { try {
return cont(x); return cont(x);
} catch(ex) { } catch (ex) {
if (ex === EX_EOF) parse_error(eof_error); if (ex === EX_EOF) parse_error(eof_error);
else throw ex; else throw ex;
} }
}; };
}; }
function next_token(force_regexp) { function next_token(force_regexp) {
if (force_regexp != null) if (force_regexp != null)
@@ -596,12 +579,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
switch (code) { switch (code) {
case 34: case 39: return read_string(ch); case 34: case 39: return read_string(ch);
case 46: return handle_dot(); case 46: return handle_dot();
case 47: { case 47:
var tok = handle_slash(); var tok = handle_slash();
if (tok === next_token) continue; if (tok === next_token) continue;
return tok; return tok;
} }
}
if (is_digit(code)) return read_num(); if (is_digit(code)) return read_num();
if (PUNC_CHARS[ch]) return token("punc", next()); if (PUNC_CHARS[ch]) return token("punc", next());
if (OPERATOR_CHARS[ch]) return read_operator(); if (OPERATOR_CHARS[ch]) return read_operator();
@@ -609,7 +591,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
break; break;
} }
parse_error("Unexpected character '" + ch + "'"); parse_error("Unexpected character '" + ch + "'");
}; }
next_token.context = function(nc) { next_token.context = function(nc) {
if (nc) S = nc; if (nc) S = nc;
@@ -618,12 +600,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
next_token.add_directive = function(directive) { next_token.add_directive = function(directive) {
S.directive_stack[S.directive_stack.length - 1].push(directive); S.directive_stack[S.directive_stack.length - 1].push(directive);
if (S.directives[directive]) S.directives[directive]++;
if (S.directives[directive] === undefined) { else S.directives[directive] = 1;
S.directives[directive] = 1;
} else {
S.directives[directive]++;
}
} }
next_token.push_directives_stack = function() { next_token.push_directives_stack = function() {
@@ -631,13 +609,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
next_token.pop_directives_stack = function() { next_token.pop_directives_stack = function() {
var directives = S.directive_stack[S.directive_stack.length - 1]; var directives = S.directive_stack.pop();
for (var i = directives.length; --i >= 0;) {
for (var i = 0; i < directives.length; i++) {
S.directives[directives[i]]--; S.directives[directives[i]]--;
} }
S.directive_stack.pop();
} }
next_token.has_directive = function(directive) { next_token.has_directive = function(directive) {
@@ -645,37 +620,25 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
return next_token; return next_token;
}
};
/* -----[ Parser (constants) ]----- */ /* -----[ Parser (constants) ]----- */
var UNARY_PREFIX = makePredicate([ var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
"typeof",
"void",
"delete",
"--",
"++",
"!",
"~",
"-",
"+"
]);
var UNARY_POSTFIX = makePredicate([ "--", "++" ]); var UNARY_POSTFIX = makePredicate("-- ++");
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); var ASSIGNMENT = makePredicate("= += -= /= *= %= >>= <<= >>>= |= ^= &=");
var PRECEDENCE = (function(a, ret){ var PRECEDENCE = function(a, ret) {
for (var i = 0; i < a.length; ++i) { for (var i = 0; i < a.length;) {
var b = a[i]; var b = a[i++];
for (var j = 0; j < b.length; ++j) { for (var j = 0; j < b.length; j++) {
ret[b[j]] = i + 1; ret[b[j]] = i;
} }
} }
return ret; return ret;
})( }([
[
["||"], ["||"],
["&&"], ["&&"],
["|"], ["|"],
@@ -686,16 +649,13 @@ var PRECEDENCE = (function(a, ret){
[">>", "<<", ">>>"], [">>", "<<", ">>>"],
["+", "-"], ["+", "-"],
["*", "/", "%"] ["*", "/", "%"]
], ], {});
{}
);
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]); var ATOMIC_START_TOKEN = makePredicate("atom num string regexp name");
/* -----[ Parser ]----- */ /* -----[ Parser ]----- */
function parse($TEXT, options) { function parse($TEXT, options) {
options = defaults(options, { options = defaults(options, {
bare_returns : false, bare_returns : false,
expression : false, expression : false,
@@ -707,10 +667,9 @@ function parse($TEXT, options) {
}, true); }, true);
var S = { var S = {
input : (typeof $TEXT == "string" input : typeof $TEXT == "string"
? tokenizer($TEXT, options.filename, ? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
options.html5_comments, options.shebang) : $TEXT,
: $TEXT),
token : null, token : null,
prev : null, prev : null,
peeked : null, peeked : null,
@@ -724,9 +683,11 @@ function parse($TEXT, options) {
function is(type, value) { function is(type, value) {
return is_token(S.token, type, value); return is_token(S.token, type, value);
}; }
function peek() { return S.peeked || (S.peeked = S.input()); }; function peek() {
return S.peeked || (S.peeked = S.input());
}
function next() { function next() {
S.prev = S.token; S.prev = S.token;
@@ -740,11 +701,11 @@ function parse($TEXT, options) {
S.token.type == "string" || is("punc", ";") S.token.type == "string" || is("punc", ";")
); );
return S.token; return S.token;
}; }
function prev() { function prev() {
return S.prev; return S.prev;
}; }
function croak(msg, line, col, pos) { function croak(msg, line, col, pos) {
var ctx = S.input.context(); var ctx = S.input.context();
@@ -753,26 +714,29 @@ function parse($TEXT, options) {
line != null ? line : ctx.tokline, line != null ? line : ctx.tokline,
col != null ? col : ctx.tokcol, col != null ? col : ctx.tokcol,
pos != null ? pos : ctx.tokpos); pos != null ? pos : ctx.tokpos);
}; }
function token_error(token, msg) { function token_error(token, msg) {
croak(msg, token.line, token.col); croak(msg, token.line, token.col);
}; }
function token_to_string(type, value) {
return type + (value === undefined ? "" : " «" + value + "»");
}
function unexpected(token) { function unexpected(token) {
if (token == null) if (token == null) token = S.token;
token = S.token; token_error(token, "Unexpected token: " + token_to_string(token.type, token.value));
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); }
};
function expect_token(type, val) { function expect_token(type, val) {
if (is(type, val)) { if (is(type, val)) return next();
return next(); token_error(S.token, "Unexpected token: " + token_to_string(S.token.type, S.token.value) + ", expected: " + token_to_string(type, val));
} }
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
};
function expect(punc) { return expect_token("punc", punc); }; function expect(punc) {
return expect_token("punc", punc);
}
function has_newline_before(token) { function has_newline_before(token) {
return token.nlb || !all(token.comments_before, function(comment) { return token.nlb || !all(token.comments_before, function(comment) {
@@ -783,19 +747,19 @@ function parse($TEXT, options) {
function can_insert_semicolon() { function can_insert_semicolon() {
return !options.strict return !options.strict
&& (is("eof") || is("punc", "}") || has_newline_before(S.token)); && (is("eof") || is("punc", "}") || has_newline_before(S.token));
}; }
function semicolon(optional) { function semicolon(optional) {
if (is("punc", ";")) next(); if (is("punc", ";")) next();
else if (!optional && !can_insert_semicolon()) unexpected(); else if (!optional && !can_insert_semicolon()) expect_token("punc", ";");
}; }
function parenthesised() { function parenthesised() {
expect("("); expect("(");
var exp = expression(true); var exp = expression(true);
expect(")"); expect(")");
return exp; return exp;
}; }
function embed_tokens(parser) { function embed_tokens(parser) {
return function() { return function() {
@@ -806,33 +770,32 @@ function parse($TEXT, options) {
expr.end = end; expr.end = end;
return expr; return expr;
}; };
}; }
function handle_regexp() { function handle_regexp() {
if (is("operator", "/") || is("operator", "/=")) { if (is("operator", "/") || is("operator", "/=")) {
S.peeked = null; S.peeked = null;
S.token = S.input(S.token.value.substr(1)); // force regexp S.token = S.input(S.token.value.substr(1)); // force regexp
} }
}; }
var statement = embed_tokens(function(strict_defun) { var statement = embed_tokens(function(strict_defun) {
handle_regexp(); handle_regexp();
switch (S.token.type) { switch (S.token.type) {
case "string": case "string":
if (S.in_directives) { var dir = S.in_directives;
var token = peek(); var body = expression(true);
if (S.token.raw.indexOf("\\") == -1 if (dir) {
&& (is_token(token, "punc", ";") if (body instanceof AST_String) {
|| is_token(token, "punc", "}") var value = body.start.raw.slice(1, -1);
|| has_newline_before(token) S.input.add_directive(value);
|| is_token(token, "eof"))) { body.value = value;
S.input.add_directive(S.token.value);
} else { } else {
S.in_directives = false; S.in_directives = dir = false;
} }
} }
var dir = S.in_directives, stat = simple_statement(); semicolon();
return dir ? new AST_Directive(stat.body) : stat; return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
case "num": case "num":
case "regexp": case "regexp":
case "operator": case "operator":
@@ -986,7 +949,7 @@ function parse($TEXT, options) {
// check for `continue` that refers to this label. // check for `continue` that refers to this label.
// those should be reported as syntax errors. // those should be reported as syntax errors.
// https://github.com/mishoo/UglifyJS2/issues/287 // https://github.com/mishoo/UglifyJS2/issues/287
label.references.forEach(function(ref){ label.references.forEach(function(ref) {
if (ref instanceof AST_Continue) { if (ref instanceof AST_Continue) {
ref = ref.label.start; ref = ref.label.start;
croak("Continue label `" + label.name + "` refers to non-IterationStatement.", croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
@@ -995,11 +958,13 @@ function parse($TEXT, options) {
}); });
} }
return new AST_LabeledStatement({ body: stat, label: label }); return new AST_LabeledStatement({ body: stat, label: label });
}; }
function simple_statement(tmp) { function simple_statement() {
return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); var body = expression(true);
}; semicolon();
return new AST_SimpleStatement({ body: body });
}
function break_cont(type) { function break_cont(type) {
var label = null, ldef; var label = null, ldef;
@@ -1007,18 +972,17 @@ function parse($TEXT, options) {
label = as_symbol(AST_LabelRef, true); label = as_symbol(AST_LabelRef, true);
} }
if (label != null) { if (label != null) {
ldef = find_if(function(l){ return l.name == label.name }, S.labels); ldef = find_if(function(l) {
if (!ldef) return l.name == label.name;
croak("Undefined label " + label.name); }, S.labels);
if (!ldef) croak("Undefined label " + label.name);
label.thedef = ldef; label.thedef = ldef;
} } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
else if (S.in_loop == 0)
croak(type.TYPE + " not inside a loop or switch");
semicolon(); semicolon();
var stat = new type({ label: label }); var stat = new type({ label: label });
if (ldef) ldef.references.push(stat); if (ldef) ldef.references.push(stat);
return stat; return stat;
}; }
function for_() { function for_() {
expect("("); expect("(");
@@ -1039,7 +1003,7 @@ function parse($TEXT, options) {
} }
} }
return regular_for(init); return regular_for(init);
}; }
function regular_for(init) { function regular_for(init) {
expect(";"); expect(";");
@@ -1053,7 +1017,7 @@ function parse($TEXT, options) {
step : step, step : step,
body : in_loop(statement) body : in_loop(statement)
}); });
}; }
function for_in(init) { function for_in(init) {
var obj = expression(true); var obj = expression(true);
@@ -1063,13 +1027,13 @@ function parse($TEXT, options) {
object : obj, object : obj,
body : in_loop(statement) body : in_loop(statement)
}); });
}; }
var function_ = function(ctor) { var function_ = function(ctor) {
var in_statement = ctor === AST_Defun; var in_statement = ctor === AST_Defun;
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
if (in_statement && !name) if (in_statement && !name)
unexpected(); expect_token("name");
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration)) if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
unexpected(prev()); unexpected(prev());
expect("("); expect("(");
@@ -1113,24 +1077,24 @@ function parse($TEXT, options) {
body : body, body : body,
alternative : belse alternative : belse
}); });
}; }
function block_(strict_defun) { function block_(strict_defun) {
expect("{"); expect("{");
var a = []; var a = [];
while (!is("punc", "}")) { while (!is("punc", "}")) {
if (is("eof")) unexpected(); if (is("eof")) expect_token("punc", "}");
a.push(statement(strict_defun)); a.push(statement(strict_defun));
} }
next(); next();
return a; return a;
}; }
function switch_body_() { function switch_body_() {
expect("{"); expect("{");
var a = [], cur = null, branch = null, tmp; var a = [], cur = null, branch = null, tmp;
while (!is("punc", "}")) { while (!is("punc", "}")) {
if (is("eof")) unexpected(); if (is("eof")) expect_token("punc", "}");
if (is("keyword", "case")) { if (is("keyword", "case")) {
if (branch) branch.end = prev(); if (branch) branch.end = prev();
cur = []; cur = [];
@@ -1141,8 +1105,7 @@ function parse($TEXT, options) {
}); });
a.push(branch); a.push(branch);
expect(":"); expect(":");
} } else if (is("keyword", "default")) {
else if (is("keyword", "default")) {
if (branch) branch.end = prev(); if (branch) branch.end = prev();
cur = []; cur = [];
branch = new AST_Default({ branch = new AST_Default({
@@ -1150,8 +1113,7 @@ function parse($TEXT, options) {
body : cur body : cur
}); });
a.push(branch); a.push(branch);
} } else {
else {
if (!cur) unexpected(); if (!cur) unexpected();
cur.push(statement()); cur.push(statement());
} }
@@ -1159,7 +1121,7 @@ function parse($TEXT, options) {
if (branch) branch.end = prev(); if (branch) branch.end = prev();
next(); next();
return a; return a;
}; }
function try_() { function try_() {
var body = block_(), bcatch = null, bfinally = null; var body = block_(), bcatch = null, bfinally = null;
@@ -1192,7 +1154,7 @@ function parse($TEXT, options) {
bcatch : bcatch, bcatch : bcatch,
bfinally : bfinally bfinally : bfinally
}); });
}; }
function vardefs(no_in) { function vardefs(no_in) {
var a = []; var a = [];
@@ -1208,7 +1170,7 @@ function parse($TEXT, options) {
next(); next();
} }
return a; return a;
}; }
var var_ = function(no_in) { var var_ = function(no_in) {
return new AST_Var({ return new AST_Var({
@@ -1274,7 +1236,7 @@ function parse($TEXT, options) {
} }
next(); next();
return ret; return ret;
}; }
var expr_atom = function(allow_calls) { var expr_atom = function(allow_calls) {
if (is("operator", "new")) { if (is("operator", "new")) {
@@ -1288,6 +1250,7 @@ function parse($TEXT, options) {
var ex = expression(true); var ex = expression(true);
var len = start.comments_before.length; var len = start.comments_before.length;
[].unshift.apply(ex.start.comments_before, start.comments_before); [].unshift.apply(ex.start.comments_before, start.comments_before);
start.comments_before.length = 0;
start.comments_before = ex.start.comments_before; start.comments_before = ex.start.comments_before;
start.comments_before_length = len; start.comments_before_length = len;
if (len == 0 && start.comments_before.length > 0) { if (len == 0 && start.comments_before.length > 0) {
@@ -1303,6 +1266,7 @@ function parse($TEXT, options) {
var end = prev(); var end = prev();
end.comments_before = ex.end.comments_before; end.comments_before = ex.end.comments_before;
[].push.apply(ex.end.comments_after, end.comments_after); [].push.apply(ex.end.comments_after, end.comments_after);
end.comments_after.length = 0;
end.comments_after = ex.end.comments_after; end.comments_after = ex.end.comments_after;
ex.end = end; ex.end = end;
if (ex instanceof AST_Call) mark_pure(ex); if (ex instanceof AST_Call) mark_pure(ex);
@@ -1340,7 +1304,7 @@ function parse($TEXT, options) {
} }
next(); next();
return a; return a;
}; }
var array_ = embed_tokens(function() { var array_ = embed_tokens(function() {
expect("["); expect("[");
@@ -1417,14 +1381,14 @@ function parse($TEXT, options) {
default: default:
unexpected(); unexpected();
} }
}; }
function as_name() { function as_name() {
var tmp = S.token; if (!is("name")) expect_token("name");
if (tmp.type != "name") unexpected(); var name = S.token.value;
next(); next();
return tmp.value; return name;
}; }
function _make_symbol(type) { function _make_symbol(type) {
var name = S.token.value; var name = S.token.value;
@@ -1433,7 +1397,7 @@ function parse($TEXT, options) {
start : S.token, start : S.token,
end : S.token end : S.token
}); });
}; }
function strict_verify_symbol(sym) { function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval") if (sym.name == "arguments" || sym.name == "eval")
@@ -1451,7 +1415,7 @@ function parse($TEXT, options) {
} }
next(); next();
return sym; return sym;
}; }
function mark_pure(call) { function mark_pure(call) {
var start = call.start; var start = call.start;
@@ -1536,7 +1500,7 @@ function parse($TEXT, options) {
break; break;
} }
return new ctor({ operator: op, expression: expr }); return new ctor({ operator: op, expression: expr });
}; }
var expr_op = function(left, min_prec, no_in) { var expr_op = function(left, min_prec, no_in) {
var op = is("operator") ? S.token.value : null; var op = is("operator") ? S.token.value : null;
@@ -1558,7 +1522,7 @@ function parse($TEXT, options) {
function expr_ops(no_in) { function expr_ops(no_in) {
return expr_op(maybe_unary(true), 0, no_in); return expr_op(maybe_unary(true), 0, no_in);
}; }
var maybe_conditional = function(no_in) { var maybe_conditional = function(no_in) {
var start = S.token; var start = S.token;
@@ -1580,7 +1544,7 @@ function parse($TEXT, options) {
function is_assignable(expr) { function is_assignable(expr) {
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
}; }
var maybe_assign = function(no_in) { var maybe_assign = function(no_in) {
var start = S.token; var start = S.token;
@@ -1622,13 +1586,14 @@ function parse($TEXT, options) {
var ret = cont(); var ret = cont();
--S.in_loop; --S.in_loop;
return ret; return ret;
}; }
if (options.expression) { if (options.expression) {
handle_regexp();
return expression(true); return expression(true);
} }
return (function(){ return function() {
var start = S.token; var start = S.token;
var body = []; var body = [];
S.input.push_directives_stack(); S.input.push_directives_stack();
@@ -1644,6 +1609,5 @@ function parse($TEXT, options) {
toplevel = new AST_Toplevel({ start: start, body: body, end: end }); toplevel = new AST_Toplevel({ start: start, body: body, end: end });
} }
return toplevel; return toplevel;
})(); }();
}
};

View File

@@ -53,25 +53,30 @@ function find_builtins(reserved) {
"-Infinity", "-Infinity",
"undefined", "undefined",
].forEach(add); ].forEach(add);
[ Object, Array, Function, Number, [
String, Boolean, Error, Math, Array,
Date, RegExp Boolean,
].forEach(function(ctor){ Date,
Error,
Function,
Math,
Number,
Object,
RegExp,
String,
].forEach(function(ctor) {
Object.getOwnPropertyNames(ctor).map(add); Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) { if (ctor.prototype) {
Object.getOwnPropertyNames(ctor.prototype).map(add); Object.getOwnPropertyNames(ctor.prototype).map(add);
} }
}); });
function add(name) { function add(name) {
push_uniq(reserved, name); push_uniq(reserved, name);
} }
} }
function reserve_quoted_keys(ast, reserved) { function reserve_quoted_keys(ast, reserved) {
function add(name) {
push_uniq(reserved, name);
}
ast.walk(new TreeWalker(function(node) { ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) { if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key); add(node.key);
@@ -79,6 +84,10 @@ function reserve_quoted_keys(ast, reserved) {
addStrings(node.property, add); addStrings(node.property, add);
} }
})); }));
function add(name) {
push_uniq(reserved, name);
}
} }
function addStrings(node, add) { function addStrings(node, add) {
@@ -127,51 +136,41 @@ function mangle_properties(ast, options) {
// 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 falsey. Also treat passing 'true'
// the same as passing an empty string. // the same as passing an empty string.
var debug = options.debug !== false; var debug = options.debug !== false;
var debug_name_suffix; var debug_suffix;
if (debug) { if (debug) debug_suffix = options.debug === true ? "" : options.debug;
debug_name_suffix = (options.debug === true ? "" : options.debug);
}
var names_to_mangle = []; var names_to_mangle = [];
var unmangleable = []; var unmangleable = [];
// step 1: find candidates to mangle // step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){ ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
add(node.key); add(node.key);
} } else if (node instanceof AST_ObjectProperty) {
else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above // setter or getter, since KeyVal is handled above
add(node.key.name); add(node.key.name);
} } else if (node instanceof AST_Dot) {
else if (node instanceof AST_Dot) {
add(node.property); add(node.property);
} } else if (node instanceof AST_Sub) {
else if (node instanceof AST_Sub) {
addStrings(node.property, add); addStrings(node.property, add);
} } else if (node instanceof AST_Call
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") { && node.expression.print_to_string() == "Object.defineProperty") {
addStrings(node.args[1], add); addStrings(node.args[1], add);
} }
})); }));
// step 2: transform the tree, renaming properties // step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){ return ast.transform(new TreeTransformer(function(node) {
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
node.key = mangle(node.key); node.key = mangle(node.key);
} } else if (node instanceof AST_ObjectProperty) {
else if (node instanceof AST_ObjectProperty) {
// setter or getter // setter or getter
node.key.name = mangle(node.key.name); node.key.name = mangle(node.key.name);
} } else if (node instanceof AST_Dot) {
else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} } else if (!options.keep_quoted && node instanceof AST_Sub) {
else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property); node.property = mangleStrings(node.property);
} } else if (node instanceof AST_Call
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") { && node.expression.print_to_string() == "Object.defineProperty") {
node.args[1] = mangleStrings(node.args[1]); node.args[1] = mangleStrings(node.args[1]);
} }
@@ -182,9 +181,7 @@ function mangle_properties(ast, options) {
function can_mangle(name) { function can_mangle(name) {
if (unmangleable.indexOf(name) >= 0) return false; if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) { if (options.only_cache) return cache.has(name);
return cache.has(name);
}
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true; return true;
} }
@@ -192,57 +189,42 @@ function mangle_properties(ast, options) {
function should_mangle(name) { function should_mangle(name) {
if (regex && !regex.test(name)) return false; if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false;
return cache.has(name) return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
|| names_to_mangle.indexOf(name) >= 0;
} }
function add(name) { function add(name) {
if (can_mangle(name)) if (can_mangle(name)) push_uniq(names_to_mangle, name);
push_uniq(names_to_mangle, name); if (!should_mangle(name)) push_uniq(unmangleable, name);
if (!should_mangle(name)) {
push_uniq(unmangleable, name);
}
} }
function mangle(name) { function mangle(name) {
if (!should_mangle(name)) { if (!should_mangle(name)) {
return name; return name;
} }
var mangled = cache.get(name); var mangled = cache.get(name);
if (!mangled) { if (!mangled) {
if (debug) { if (debug) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
if (can_mangle(debug_mangled)) mangled = debug_mangled;
if (can_mangle(debug_mangled)) {
mangled = debug_mangled;
} }
}
// either debug mode is off, or it is on and we could not use the mangled name // either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) { if (!mangled) do {
do {
mangled = base54(++cname); mangled = base54(++cname);
} while (!can_mangle(mangled)); } while (!can_mangle(mangled));
}
cache.set(name, mangled); cache.set(name, mangled);
} }
return mangled; return mangled;
} }
function mangleStrings(node) { function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){ return node.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1; var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]); node.expressions[last] = mangleStrings(node.expressions[last]);
} } else if (node instanceof AST_String) {
else if (node instanceof AST_String) {
node.value = mangle(node.value); node.value = mangle(node.value);
} } else if (node instanceof AST_Conditional) {
else if (node instanceof AST_Conditional) {
node.consequent = mangleStrings(node.consequent); node.consequent = mangleStrings(node.consequent);
node.alternative = mangleStrings(node.alternative); node.alternative = mangleStrings(node.alternative);
} }

View File

@@ -55,20 +55,19 @@ function SymbolDef(scope, orig, init) {
this.mangled_name = null; this.mangled_name = null;
this.undeclared = false; this.undeclared = false;
this.id = SymbolDef.next_id++; this.id = SymbolDef.next_id++;
}; this.lambda = orig instanceof AST_SymbolLambda;
}
SymbolDef.next_id = 1; SymbolDef.next_id = 1;
SymbolDef.prototype = { SymbolDef.prototype = {
unmangleable: function(options) { unmangleable: function(options) {
if (!options) options = {}; return this.global && !options.toplevel
return (this.global && !options.toplevel)
|| this.undeclared || this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with)) || !options.eval && this.scope.pinned()
|| (options.keep_fnames || options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda && (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun)); || this.orig[0] instanceof AST_SymbolDefun);
}, },
mangle: function(options) { mangle: function(options) {
var cache = options.cache && options.cache.props; var cache = options.cache && options.cache.props;
@@ -91,7 +90,7 @@ SymbolDef.prototype = {
} }
}; };
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
options = defaults(options, { options = defaults(options, {
cache: null, cache: null,
ie8: false, ie8: false,
@@ -101,7 +100,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var self = this; var self = this;
var scope = self.parent_scope = null; var scope = self.parent_scope = null;
var defun = null; var defun = null;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Catch) { if (node instanceof AST_Catch) {
var save_scope = scope; var save_scope = scope;
scope = new AST_Scope(node); scope = new AST_Scope(node);
@@ -118,11 +117,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
descend(); descend();
scope = save_scope; scope = save_scope;
defun = save_defun; defun = save_defun;
return true; // don't descend again in TreeWalker return true;
} }
if (node instanceof AST_With) { if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope) for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
s.uses_with = true;
return; return;
} }
if (node instanceof AST_Symbol) { if (node instanceof AST_Symbol) {
@@ -132,18 +130,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.thedef = node; node.thedef = node;
node.references = []; node.references = [];
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolDefun) {
defun.def_function(node, node.name == "arguments" ? undefined : defun); // This should be defined in the parent scope, as we encounter the
} // AST_Defun node before getting to its AST_Symbol.
else if (node instanceof AST_SymbolDefun) { (node.scope = defun.parent_scope.resolve()).def_function(node, defun);
// Careful here, the scope where this should be defined is } else if (node instanceof AST_SymbolLambda) {
// the parent scope. The reason is that we enter a new var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
// scope when we encounter the AST_Defun node (which is if (options.ie8) def.defun = defun.parent_scope.resolve();
// instanceof AST_Scope) but we get to the symbol a bit } else if (node instanceof AST_SymbolVar) {
// later.
(node.scope = defun.parent_scope).def_function(node, defun);
}
else if (node instanceof AST_SymbolVar) {
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined); defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
if (defun !== scope) { if (defun !== scope) {
node.mark_enclosed(options); node.mark_enclosed(options);
@@ -153,8 +147,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
} }
node.reference(options); node.reference(options);
} }
} } else if (node instanceof AST_SymbolCatch) {
else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun; scope.def_variable(node).defun = defun;
} }
}); });
@@ -162,62 +155,92 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// pass 2: find back references and eval // pass 2: find back references and eval
self.globals = new Dictionary(); self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node) {
if (node instanceof AST_LoopControl && node.label) { if (node instanceof AST_LoopControl) {
node.label.thedef.references.push(node); if (node.label) node.label.thedef.references.push(node);
return true; return true;
} }
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var name = node.name; var name = node.name;
if (name == "eval" && tw.parent() instanceof AST_Call) {
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
s.uses_eval = true;
}
}
var sym = node.scope.find_variable(name); var sym = node.scope.find_variable(name);
if (!sym) { if (!sym) {
sym = self.def_global(node); sym = self.def_global(node);
} else if (sym.scope instanceof AST_Lambda && name == "arguments") { } else if (sym.scope instanceof AST_Lambda && name == "arguments") {
sym.scope.uses_arguments = true; sym.scope.uses_arguments = true;
} }
if (name == "eval") {
var parent = tw.parent();
if (parent.TYPE == "Call" && parent.expression === node) {
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
s.uses_eval = true;
}
} else if (sym.undeclared) {
self.uses_eval = true;
}
}
node.thedef = sym; node.thedef = sym;
node.reference(options); node.reference(options);
return true; return true;
} }
// ensure mangling works if catch reuses a scope variable // ensure mangling works if catch reuses a scope variable
var def; if (node instanceof AST_SymbolCatch) {
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) { var def = node.definition().redefined();
var s = node.scope; if (def) for (var s = node.scope; s; s = s.parent_scope) {
while (s) {
push_uniq(s.enclosed, def); push_uniq(s.enclosed, def);
if (s === def.scope) break; if (s === def.scope) break;
s = s.parent_scope;
} }
return true;
} }
}); });
self.walk(tw); self.walk(tw);
// pass 3: fix up any scoping issue with IE8 // pass 3: fix up any scoping issue with IE8
if (options.ie8) { if (options.ie8) self.walk(new TreeWalker(function(node) {
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) { if (node instanceof AST_SymbolCatch) {
var name = node.name;
var refs = node.thedef.references;
var scope = node.thedef.defun; var scope = node.thedef.defun;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
refs.forEach(function(ref) { scope = scope.parent_scope.resolve();
ref.thedef = def; }
ref.reference(options); redefine(node, scope);
}); return true;
node.thedef = def; }
node.reference(options); if (node instanceof AST_SymbolLambda) {
var def = node.thedef;
redefine(node, node.scope.parent_scope.resolve());
if (typeof node.thedef.init !== "undefined") {
node.thedef.init = false;
} else if (def.init) {
node.thedef.init = def.init;
}
return true; return true;
} }
})); }));
function redefine(node, scope) {
var name = node.name;
var old_def = node.thedef;
var new_def = scope.find_variable(name);
if (new_def) {
var redef;
while (redef = new_def.redefined()) new_def = redef;
} else {
new_def = self.globals.get(name);
}
if (new_def) {
new_def.orig.push(node);
} else {
new_def = scope.def_variable(node);
}
old_def.orig.concat(old_def.references).forEach(function(node) {
node.thedef = new_def;
node.reference(options);
});
if (old_def.lambda) new_def.lambda = true;
if (new_def.undeclared) self.variables.set(name, new_def);
} }
}); });
AST_Toplevel.DEFMETHOD("def_global", function(node){ AST_Toplevel.DEFMETHOD("def_global", function(node) {
var globals = this.globals, name = node.name; var globals = this.globals, name = node.name;
if (globals.has(name)) { if (globals.has(name)) {
return globals.get(name); return globals.get(name);
@@ -230,7 +253,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
} }
}); });
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -240,7 +263,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.cname = -1; // the current index for mangling functions/variables this.cname = -1; // the current index for mangling functions/variables
}); });
AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Lambda.DEFMETHOD("init_scope_vars", function() {
AST_Scope.prototype.init_scope_vars.apply(this, arguments); AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false; this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({ this.def_variable(new AST_SymbolFunarg({
@@ -252,8 +275,7 @@ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition(); var def = this.definition();
var s = this.scope; for (var s = this.scope; s; s = s.parent_scope) {
while (s) {
push_uniq(s.enclosed, def); push_uniq(s.enclosed, def);
if (options.keep_fnames) { if (options.keep_fnames) {
s.functions.each(function(d) { s.functions.each(function(d) {
@@ -261,7 +283,6 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
}); });
} }
if (s === def.scope) break; if (s === def.scope) break;
s = s.parent_scope;
} }
}); });
@@ -270,26 +291,24 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
this.mark_enclosed(options); this.mark_enclosed(options);
}); });
AST_Scope.DEFMETHOD("find_variable", function(name){ AST_Scope.DEFMETHOD("find_variable", function(name) {
if (name instanceof AST_Symbol) name = name.name; if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name) return this.variables.get(name)
|| (this.parent_scope && this.parent_scope.find_variable(name)); || (this.parent_scope && this.parent_scope.find_variable(name));
}); });
AST_Scope.DEFMETHOD("def_function", function(symbol, init){ AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
var def = this.def_variable(symbol, init); var def = this.def_variable(symbol, init);
if (!def.init || def.init instanceof AST_Defun) def.init = init; if (!def.init || def.init instanceof AST_Defun) def.init = init;
this.functions.set(symbol.name, def); this.functions.set(symbol.name, def);
return def; return def;
}); });
AST_Scope.DEFMETHOD("def_variable", function(symbol, init){ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name); var def = this.variables.get(symbol.name);
if (def) { if (def) {
def.orig.push(symbol); def.orig.push(symbol);
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) { if (def.init instanceof AST_Function) def.init = init;
def.init = init;
}
} else { } else {
def = new SymbolDef(this, symbol, init); def = new SymbolDef(this, symbol, init);
this.variables.set(symbol.name, def); this.variables.set(symbol.name, def);
@@ -298,13 +317,23 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
return symbol.thedef = def; return symbol.thedef = def;
}); });
AST_Lambda.DEFMETHOD("resolve", return_this);
AST_Scope.DEFMETHOD("resolve", function() {
return this.parent_scope.resolve();
});
AST_Toplevel.DEFMETHOD("resolve", return_this);
function names_in_use(scope, options) { function names_in_use(scope, options) {
var names = scope.names_in_use; var names = scope.names_in_use;
if (!names) { if (!names) {
scope.names_in_use = names = Object.create(scope.mangled_names || null); scope.names_in_use = names = Object.create(scope.mangled_names || null);
scope.cname_holes = []; scope.cname_holes = [];
var cache = options.cache && options.cache.props;
scope.enclosed.forEach(function(def) { scope.enclosed.forEach(function(def) {
if (def.unmangleable(options)) names[def.name] = true; if (def.unmangleable(options)) names[def.name] = true;
if (def.global && cache && cache.has(def.name)) {
names[cache.get(def.name)] = true;
}
}); });
} }
return names; return names;
@@ -314,14 +343,6 @@ function next_mangled_name(scope, options, def) {
var in_use = names_in_use(scope, options); var in_use = names_in_use(scope, options);
var holes = scope.cname_holes; var holes = scope.cname_holes;
var names = Object.create(null); var names = Object.create(null);
// #179, #326
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
// a function expression's argument cannot shadow the function expression's name
if (scope instanceof AST_Function && scope.name && def.orig[0] instanceof AST_SymbolFunarg) {
var tricky_def = scope.name.definition();
// the function's mangled_name is null when keep_fnames is true
names[tricky_def.mangled_name || tricky_def.name] = true;
}
var scopes = [ scope ]; var scopes = [ scope ];
def.references.forEach(function(sym) { def.references.forEach(function(sym) {
var scope = sym.scope; var scope = sym.scope;
@@ -335,7 +356,7 @@ function next_mangled_name(scope, options, def) {
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
}); });
var name; var name;
for (var i = 0, len = holes.length; i < len; i++) { for (var i = 0; i < holes.length; i++) {
name = base54(holes[i]); name = base54(holes[i]);
if (names[name]) continue; if (names[name]) continue;
holes.splice(i, 1); holes.splice(i, 1);
@@ -344,18 +365,15 @@ function next_mangled_name(scope, options, def) {
} }
while (true) { while (true) {
name = base54(++scope.cname); name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue; if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names[name]) break; if (!names[name]) break;
holes.push(scope.cname); holes.push(scope.cname);
} }
scope.names_in_use[name] = true; scope.names_in_use[name] = true;
if (options.ie8 && def.orig[0] instanceof AST_SymbolLambda) {
names_in_use(scope.parent_scope, options)[name] = true;
}
return name; return name;
} }
AST_Symbol.DEFMETHOD("unmangleable", function(options){ AST_Symbol.DEFMETHOD("unmangleable", function(options) {
var def = this.definition(); var def = this.definition();
return !def || def.unmangleable(options); return !def || def.unmangleable(options);
}); });
@@ -363,16 +381,15 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
// labels are always mangleable // labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", return_false); AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function(){ AST_Symbol.DEFMETHOD("unreferenced", function() {
return this.definition().references.length == 0 return !this.definition().references.length && !this.scope.pinned();
&& !(this.scope.uses_eval || this.scope.uses_with);
}); });
AST_Symbol.DEFMETHOD("definition", function(){ AST_Symbol.DEFMETHOD("definition", function() {
return this.thedef; return this.thedef;
}); });
AST_Symbol.DEFMETHOD("global", function(){ AST_Symbol.DEFMETHOD("global", function() {
return this.definition().global; return this.definition().global;
}); });
@@ -391,7 +408,7 @@ function _default_mangler_options(options) {
return options; return options;
} }
AST_Toplevel.DEFMETHOD("mangle_names", function(options){ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
options = _default_mangler_options(options); options = _default_mangler_options(options);
// We only need to mangle declaration nodes. Special logic wired // We only need to mangle declaration nodes. Special logic wired
@@ -408,46 +425,44 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
} }
var redefined = []; var redefined = [];
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LabeledStatement) { if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label // lname is incremented when we get to the AST_Label
var save_nesting = lname; var save_nesting = lname;
descend(); descend();
lname = save_nesting; lname = save_nesting;
return true; // don't descend again in TreeWalker return true;
} }
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
descend(); descend();
if (options.cache && node instanceof AST_Toplevel) { if (options.cache && node instanceof AST_Toplevel) {
node.globals.each(mangle); node.globals.each(mangle);
} }
node.variables.each(mangle); if (node instanceof AST_Defun && tw.has_directive("use asm")) {
var sym = new AST_SymbolRef(node.name);
sym.scope = node;
sym.reference(options);
}
node.variables.each(function(def) {
if (!defer_redef(def)) mangle(def);
});
return true; return true;
} }
if (node instanceof AST_Label) { if (node instanceof AST_Label) {
var name; var name;
do name = base54(++lname); while (!is_identifier(name)); do {
name = base54(++lname);
} while (RESERVED_WORDS[name]);
node.mangled_name = name; node.mangled_name = name;
return true; return true;
} }
if (!options.ie8 && node instanceof AST_Catch) { if (!options.ie8 && node instanceof AST_Catch) {
var def = node.argname.definition(); var def = node.argname.definition();
var redef = def.redefined(); var redef = defer_redef(def, node.argname);
if (redef) {
redefined.push(def);
reference(node.argname);
def.references.forEach(reference);
}
descend(); descend();
if (!redef) mangle(def); if (!redef) mangle(def);
return true; return true;
} }
function reference(sym) {
sym.thedef = redef;
sym.reference(options);
sym.thedef = def;
}
}); });
this.walk(tw); this.walk(tw);
redefined.forEach(mangle); redefined.forEach(mangle);
@@ -456,6 +471,21 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (options.reserved.has[def.name]) return; if (options.reserved.has[def.name]) return;
def.mangle(options); def.mangle(options);
} }
function defer_redef(def, node) {
var redef = def.redefined();
if (!redef) return false;
redefined.push(def);
def.references.forEach(reference);
if (node) reference(node);
return true;
function reference(sym) {
sym.thedef = redef;
sym.reference(options);
sym.thedef = def;
}
}
}); });
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) { AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
@@ -497,7 +527,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var name; var name;
do { do {
name = base54(cname++); name = base54(cname++);
} while (avoid[name] || !is_identifier(name)); } while (avoid[name] || RESERVED_WORDS[name]);
return name; return name;
} }
@@ -505,13 +535,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
if (def.global && options.cache) return; if (def.global && options.cache) return;
if (def.unmangleable(options)) return; if (def.unmangleable(options)) return;
if (options.reserved.has[def.name]) return; if (options.reserved.has[def.name]) return;
var d = def.redefined(); var redef = def.redefined();
def.name = d ? d.name : next_name(); var name = redef ? redef.rename || redef.name : next_name();
def.rename = name;
def.orig.forEach(function(sym) { def.orig.forEach(function(sym) {
sym.name = def.name; sym.name = name;
}); });
def.references.forEach(function(sym) { def.references.forEach(function(sym) {
sym.name = def.name; sym.name = name;
}); });
} }
}); });
@@ -521,7 +552,7 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1]; return this.expressions[this.expressions.length - 1];
}); });
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
options = _default_mangler_options(options); options = _default_mangler_options(options);
base54.reset(); base54.reset();
try { try {
@@ -556,17 +587,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
}); });
var base54 = (function() { var base54 = (function() {
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); var freq = Object.create(null);
var digits = "0123456789".split(""); function init(chars) {
var array = [];
for (var i = 0; i < chars.length; i++) {
var ch = chars[i];
array.push(ch);
freq[ch] = -1e-2 * i;
}
return array;
}
var digits = init("0123456789");
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
var chars, frequency; var chars, frequency;
function reset() { function reset() {
frequency = Object.create(null); frequency = Object.create(freq);
leading.forEach(function(ch) {
frequency[ch] = 0;
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
} }
base54.consider = function(str, delta) { base54.consider = function(str, delta) {
for (var i = str.length; --i >= 0;) { for (var i = str.length; --i >= 0;) {
@@ -577,7 +612,7 @@ var base54 = (function() {
return frequency[b] - frequency[a]; return frequency[b] - frequency[a];
} }
base54.sort = function() { base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); chars = leading.sort(compare).concat(digits.sort(compare));
}; };
base54.reset = reset; base54.reset = reset;
reset(); reset();
@@ -591,6 +626,6 @@ var base54 = (function() {
base = 64; base = 64;
} while (num > 0); } while (num > 0);
return ret; return ret;
}; }
return base54; return base54;
})(); })();

View File

@@ -43,55 +43,148 @@
"use strict"; "use strict";
// a small wrapper around fitzgen's source-map library var vlq_char = characters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
var vlq_bits = vlq_char.reduce(function(map, ch, bits) {
map[ch] = bits;
return map;
}, Object.create(null));
function vlq_decode(indices, str) {
var value = 0;
var shift = 0;
for (var i = 0, j = 0; i < str.length; i++) {
var bits = vlq_bits[str[i]];
value += (bits & 31) << shift;
if (bits & 32) {
shift += 5;
} else {
indices[j++] += value & 1 ? 0x80000000 | -(value >> 1) : value >> 1;
value = shift = 0;
}
}
return j;
}
function vlq_encode(num) {
var result = "";
num = Math.abs(num) << 1 | num >>> 31;
do {
var bits = num & 31;
if (num >>>= 5) bits |= 32;
result += vlq_char[bits];
} while (num);
return result;
}
function create_array_map() {
var map = Object.create(null);
var array = [];
array.index = function(name) {
if (!HOP(map, name)) {
map[name] = array.length;
array.push(name);
}
return map[name];
};
return array;
}
function SourceMap(options) { function SourceMap(options) {
options = defaults(options, { options = defaults(options, {
file : null, content: false,
root : null, file: null,
orig : null, root: null,
orig: null,
orig_line_diff : 0, }, true);
dest_line_diff : 0, var sources = create_array_map();
var sources_content = options.content && Object.create(null);
var names = create_array_map();
var mappings = "";
if (options.orig) Object.keys(options.orig).forEach(function(name) {
var map = options.orig[name];
var indices = [ 0, 0, 1, 0, 0 ];
options.orig[name] = {
names: map.names,
mappings: map.mappings.split(/;/).map(function(line) {
indices[0] = 0;
return line.split(/,/).map(function(segment) {
return indices.slice(0, vlq_decode(indices, segment));
}); });
var generator = new MOZ_SourceMap.SourceMapGenerator({ }),
file : options.file, sources: map.sources,
sourceRoot : options.root };
if (!sources_content || !map.sourcesContent) return;
for (var i = 0; i < map.sources.length; i++) {
var content = map.sourcesContent[i];
if (content) sources_content[map.sources[i]] = content;
}
}); });
var maps = options.orig && Object.create(null); var generated_line = 1;
if (maps) for (var source in options.orig) { var generated_column = 0;
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]); var source_index = 0;
if (Array.isArray(options.orig[source].sources)) { var original_line = 1;
map._sources.toArray().forEach(function(source) { var original_column = 0;
var sourceContent = map.sourceContentFor(source, true); var name_index = 0;
if (sourceContent) generator.setSourceContent(source, sourceContent); return {
add: options.orig ? function(source, gen_line, gen_col, orig_line, orig_col, name) {
var map = options.orig[source];
if (map) {
var segments = map.mappings[orig_line - 1];
if (!segments) return;
var indices;
for (var i = 0; i < segments.length; i++) {
var col = segments[i][0];
if (orig_col >= col) indices = segments[i];
if (orig_col <= col) break;
}
if (!indices || indices.length < 4) return;
source = map.sources[indices[1]];
orig_line = indices[2];
orig_col = indices[3];
if (indices.length > 4) name = map.names[indices[4]];
}
add(source, gen_line, gen_col, orig_line, orig_col, name);
} : add,
setSourceContent: sources_content ? function(source, content) {
sources_content[source] = content;
} : noop,
toString: function() {
return JSON.stringify({
version: 3,
file: options.file || undefined,
sourceRoot: options.root || undefined,
sources: sources,
sourcesContent: sources_content ? sources.map(function(source) {
return sources_content[source] || null;
}) : undefined,
names: names,
mappings: mappings,
}); });
} }
maps[source] = map; };
}
function add(source, gen_line, gen_col, orig_line, orig_col, name) { function add(source, gen_line, gen_col, orig_line, orig_col, name) {
var map = maps && maps[source]; if (generated_line < gen_line) {
if (map) { generated_column = 0;
var info = map.originalPositionFor({ do {
line: orig_line, mappings += ";";
column: orig_col } while (++generated_line < gen_line);
}); } else if (mappings) {
if (info.source === null) return; mappings += ",";
source = info.source;
orig_line = info.line;
orig_col = info.column;
name = info.name || name;
} }
generator.addMapping({ mappings += vlq_encode(gen_col - generated_column);
generated : { line: gen_line + options.dest_line_diff, column: gen_col }, generated_column = gen_col;
original : { line: orig_line + options.orig_line_diff, column: orig_col }, var src_idx = sources.index(source);
source : source, mappings += vlq_encode(src_idx - source_index);
name : name source_index = src_idx;
}); mappings += vlq_encode(orig_line - original_line);
}; original_line = orig_line;
return { mappings += vlq_encode(orig_col - original_column);
add : add, original_column = orig_col;
get : function() { return generator }, if (name != null) {
toString : function() { return JSON.stringify(generator.toJSON()); } var name_idx = names.index(name);
}; mappings += vlq_encode(name_idx - name_index);
}; name_index = name_idx;
}
}
}

View File

@@ -43,8 +43,6 @@
"use strict"; "use strict";
// Tree transformer helpers.
function TreeTransformer(before, after) { function TreeTransformer(before, after) {
TreeWalker.call(this); TreeWalker.call(this);
this.before = before; this.before = before;
@@ -52,168 +50,136 @@ function TreeTransformer(before, after) {
} }
TreeTransformer.prototype = new TreeWalker; TreeTransformer.prototype = new TreeWalker;
(function(undefined){ (function(DEF) {
function _(node, descend) {
node.DEFMETHOD("transform", function(tw, in_list){
var x, y;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (x === undefined) {
x = this;
descend(x, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (y !== undefined) x = y;
}
}
tw.pop();
return x;
});
};
function do_list(list, tw) { function do_list(list, tw) {
return MAP(list, function(node){ return List(list, function(node) {
return node.transform(tw, true); return node.transform(tw, true);
}); });
}; }
_(AST_Node, noop); DEF(AST_Node, noop);
DEF(AST_LabeledStatement, function(self, tw) {
_(AST_LabeledStatement, function(self, tw){
self.label = self.label.transform(tw); self.label = self.label.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_SimpleStatement, function(self, tw) {
_(AST_SimpleStatement, function(self, tw){
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_Block, function(self, tw) {
_(AST_Block, function(self, tw){
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
DEF(AST_Do, function(self, tw) {
_(AST_Do, function(self, tw){
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw); self.condition = self.condition.transform(tw);
}); });
DEF(AST_While, function(self, tw) {
_(AST_While, function(self, tw){
self.condition = self.condition.transform(tw); self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_For, function(self, tw) {
_(AST_For, function(self, tw){
if (self.init) self.init = self.init.transform(tw); if (self.init) self.init = self.init.transform(tw);
if (self.condition) self.condition = self.condition.transform(tw); if (self.condition) self.condition = self.condition.transform(tw);
if (self.step) self.step = self.step.transform(tw); if (self.step) self.step = self.step.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_ForIn, function(self, tw) {
_(AST_ForIn, function(self, tw){
self.init = self.init.transform(tw); self.init = self.init.transform(tw);
self.object = self.object.transform(tw); self.object = self.object.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_With, function(self, tw) {
_(AST_With, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
}); });
DEF(AST_Exit, function(self, tw) {
_(AST_Exit, function(self, tw){
if (self.value) self.value = self.value.transform(tw); if (self.value) self.value = self.value.transform(tw);
}); });
DEF(AST_LoopControl, function(self, tw) {
_(AST_LoopControl, function(self, tw){
if (self.label) self.label = self.label.transform(tw); if (self.label) self.label = self.label.transform(tw);
}); });
DEF(AST_If, function(self, tw) {
_(AST_If, function(self, tw){
self.condition = self.condition.transform(tw); self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw); self.body = self.body.transform(tw);
if (self.alternative) self.alternative = self.alternative.transform(tw); if (self.alternative) self.alternative = self.alternative.transform(tw);
}); });
DEF(AST_Switch, function(self, tw) {
_(AST_Switch, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
DEF(AST_Case, function(self, tw) {
_(AST_Case, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
DEF(AST_Try, function(self, tw) {
_(AST_Try, function(self, tw){
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
if (self.bcatch) self.bcatch = self.bcatch.transform(tw); if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
if (self.bfinally) self.bfinally = self.bfinally.transform(tw); if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
}); });
DEF(AST_Catch, function(self, tw) {
_(AST_Catch, function(self, tw){
self.argname = self.argname.transform(tw); self.argname = self.argname.transform(tw);
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
DEF(AST_Definitions, function(self, tw) {
_(AST_Definitions, function(self, tw){
self.definitions = do_list(self.definitions, tw); self.definitions = do_list(self.definitions, tw);
}); });
DEF(AST_VarDef, function(self, tw) {
_(AST_VarDef, function(self, tw){
self.name = self.name.transform(tw); self.name = self.name.transform(tw);
if (self.value) self.value = self.value.transform(tw); if (self.value) self.value = self.value.transform(tw);
}); });
DEF(AST_Lambda, function(self, tw) {
_(AST_Lambda, function(self, tw){
if (self.name) self.name = self.name.transform(tw); if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw); self.argnames = do_list(self.argnames, tw);
self.body = do_list(self.body, tw); self.body = do_list(self.body, tw);
}); });
DEF(AST_Call, function(self, tw) {
_(AST_Call, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw); self.args = do_list(self.args, tw);
}); });
DEF(AST_Sequence, function(self, tw) {
_(AST_Sequence, function(self, tw){
self.expressions = do_list(self.expressions, tw); self.expressions = do_list(self.expressions, tw);
}); });
DEF(AST_Dot, function(self, tw) {
_(AST_Dot, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
}); });
DEF(AST_Sub, function(self, tw) {
_(AST_Sub, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
self.property = self.property.transform(tw); self.property = self.property.transform(tw);
}); });
DEF(AST_Unary, function(self, tw) {
_(AST_Unary, function(self, tw){
self.expression = self.expression.transform(tw); self.expression = self.expression.transform(tw);
}); });
DEF(AST_Binary, function(self, tw) {
_(AST_Binary, function(self, tw){
self.left = self.left.transform(tw); self.left = self.left.transform(tw);
self.right = self.right.transform(tw); self.right = self.right.transform(tw);
}); });
DEF(AST_Conditional, function(self, tw) {
_(AST_Conditional, function(self, tw){
self.condition = self.condition.transform(tw); self.condition = self.condition.transform(tw);
self.consequent = self.consequent.transform(tw); self.consequent = self.consequent.transform(tw);
self.alternative = self.alternative.transform(tw); self.alternative = self.alternative.transform(tw);
}); });
DEF(AST_Array, function(self, tw) {
_(AST_Array, function(self, tw){
self.elements = do_list(self.elements, tw); self.elements = do_list(self.elements, tw);
}); });
DEF(AST_Object, function(self, tw) {
_(AST_Object, function(self, tw){
self.properties = do_list(self.properties, tw); self.properties = do_list(self.properties, tw);
}); });
DEF(AST_ObjectProperty, function(self, tw) {
_(AST_ObjectProperty, function(self, tw){
self.value = self.value.transform(tw); self.value = self.value.transform(tw);
}); });
})(function(node, descend) {
})(); node.DEFMETHOD("transform", function(tw, in_list) {
var x, y;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (typeof x === "undefined") {
x = this;
descend(x, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (typeof y !== "undefined") x = y;
}
}
tw.pop();
return x;
});
});

View File

@@ -45,27 +45,23 @@
function characters(str) { function characters(str) {
return str.split(""); return str.split("");
}; }
function member(name, array) { function member(name, array) {
return array.indexOf(name) >= 0; return array.indexOf(name) >= 0;
}; }
function find_if(func, array) { function find_if(func, array) {
for (var i = 0, n = array.length; i < n; ++i) { for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i];
if (func(array[i])) }
return array[i];
}
};
function repeat_string(str, i) { function repeat_string(str, i) {
if (i <= 0) return ""; if (i <= 0) return "";
if (i == 1) return str; if (i == 1) return str;
var d = repeat_string(str, i >> 1); var d = repeat_string(str, i >> 1);
d += d; d += d;
if (i & 1) d += str; return i & 1 ? d + str : d;
return d; }
};
function configure_error_stack(fn) { function configure_error_stack(fn) {
Object.defineProperty(fn.prototype, "stack", { Object.defineProperty(fn.prototype, "stack", {
@@ -74,7 +70,7 @@ function configure_error_stack(fn) {
err.name = this.name; err.name = this.name;
try { try {
throw err; throw err;
} catch(e) { } catch (e) {
return e.stack; return e.stack;
} }
} }
@@ -84,27 +80,23 @@ function configure_error_stack(fn) {
function DefaultsError(msg, defs) { function DefaultsError(msg, defs) {
this.message = msg; this.message = msg;
this.defs = defs; this.defs = defs;
}; }
DefaultsError.prototype = Object.create(Error.prototype); DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError; DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError"; DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError); configure_error_stack(DefaultsError);
DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs);
};
function defaults(args, defs, croak) { function defaults(args, defs, croak) {
if (args === true) if (args === true) args = {};
args = {};
var ret = args || {}; var ret = args || {};
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
DefaultsError.croak("`" + i + "` is not a supported option", defs); throw new DefaultsError("`" + i + "` is not a supported option", defs);
}
for (var i in defs) if (HOP(defs, i)) { for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
} }
return ret; return ret;
}; }
function merge(obj, ext) { function merge(obj, ext) {
var count = 0; var count = 0;
@@ -113,7 +105,7 @@ function merge(obj, ext) {
count++; count++;
} }
return count; return count;
}; }
function noop() {} function noop() {}
function return_false() { return false; } function return_false() { return false; }
@@ -121,8 +113,8 @@ function return_true() { return true; }
function return_this() { return this; } function return_this() { return this; }
function return_null() { return null; } function return_null() { return null; }
var MAP = (function(){ var List = (function() {
function MAP(a, f, backwards) { function List(a, f, backwards) {
var ret = [], top = [], i; var ret = [], top = [], i;
function doit() { function doit() {
var val = f(a[i], i); var val = f(a[i], i);
@@ -135,8 +127,7 @@ var MAP = (function(){
} else { } else {
top.push(val); top.push(val);
} }
} } else if (val !== skip) {
else if (val !== skip) {
if (val instanceof Splice) { if (val instanceof Splice) {
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
} else { } else {
@@ -144,7 +135,7 @@ var MAP = (function(){
} }
} }
return is_last; return is_last;
}; }
if (Array.isArray(a)) { if (Array.isArray(a)) {
if (backwards) { if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break; for (i = a.length; --i >= 0;) if (doit()) break;
@@ -153,62 +144,35 @@ var MAP = (function(){
} else { } else {
for (i = 0; i < a.length; ++i) if (doit()) break; for (i = 0; i < a.length; ++i) if (doit()) break;
} }
} } else {
else {
for (i in a) if (HOP(a, i)) if (doit()) break; for (i in a) if (HOP(a, i)) if (doit()) break;
} }
return top.concat(ret); return top.concat(ret);
}; }
MAP.at_top = function(val) { return new AtTop(val) }; List.at_top = function(val) { return new AtTop(val); };
MAP.splice = function(val) { return new Splice(val) }; List.splice = function(val) { return new Splice(val); };
MAP.last = function(val) { return new Last(val) }; List.last = function(val) { return new Last(val); };
var skip = MAP.skip = {}; var skip = List.skip = {};
function AtTop(val) { this.v = val }; function AtTop(val) { this.v = val; }
function Splice(val) { this.v = val }; function Splice(val) { this.v = val; }
function Last(val) { this.v = val }; function Last(val) { this.v = val; }
return MAP; return List;
})(); })();
function push_uniq(array, el) { function push_uniq(array, el) {
if (array.indexOf(el) < 0) if (array.indexOf(el) < 0) return array.push(el);
array.push(el); }
};
function string_template(text, props) { function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){ return text.replace(/\{(.+?)\}/g, function(str, p) {
return props && props[p]; return props && props[p];
}); });
}; }
function remove(array, el) { function remove(array, el) {
for (var i = array.length; --i >= 0;) { var index = array.indexOf(el);
if (array[i] === el) array.splice(i, 1); if (index >= 0) array.splice(index, 1);
} }
};
function mergeSort(array, cmp) {
if (array.length < 2) return array.slice();
function merge(a, b) {
var r = [], ai = 0, bi = 0, i = 0;
while (ai < a.length && bi < b.length) {
cmp(a[ai], b[bi]) <= 0
? r[i++] = a[ai++]
: r[i++] = b[bi++];
}
if (ai < a.length) r.push.apply(r, a.slice(ai));
if (bi < b.length) r.push.apply(r, b.slice(bi));
return r;
};
function _ms(a) {
if (a.length <= 1)
return a;
var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
left = _ms(left);
right = _ms(right);
return merge(left, right);
};
return _ms(array);
};
function makePredicate(words) { function makePredicate(words) {
if (!Array.isArray(words)) words = words.split(" "); if (!Array.isArray(words)) words = words.split(" ");
@@ -221,15 +185,15 @@ function makePredicate(words) {
function all(array, predicate) { function all(array, predicate) {
for (var i = array.length; --i >= 0;) for (var i = array.length; --i >= 0;)
if (!predicate(array[i])) if (!predicate(array[i], i))
return false; return false;
return true; return true;
}; }
function Dictionary() { function Dictionary() {
this._values = Object.create(null); this._values = Object.create(null);
this._size = 0; this._size = 0;
}; }
Dictionary.prototype = { Dictionary.prototype = {
set: function(key, val) { set: function(key, val) {
if (!this.has(key)) ++this._size; if (!this.has(key)) ++this._size;
@@ -253,6 +217,12 @@ Dictionary.prototype = {
return this; return this;
}, },
has: function(key) { return ("$" + key) in this._values }, has: function(key) { return ("$" + key) in this._values },
all: function(predicate) {
for (var i in this._values)
if (!predicate(this._values[i], i.substr(1)))
return false;
return true;
},
each: function(f) { each: function(f) {
for (var i in this._values) for (var i in this._values)
f(this._values[i], i.substr(1)); f(this._values[i], i.substr(1));
@@ -290,20 +260,22 @@ function HOP(obj, prop) {
// a statement. // a statement.
function first_in_statement(stack) { function first_in_statement(stack) {
var node = stack.parent(-1); var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i); i++) { for (var i = 0, p; p = stack.parent(i++); node = p) {
if (p instanceof AST_Statement && p.body === node) if (p.TYPE == "Call") {
return true; if (p.expression === node) continue;
if ((p instanceof AST_Sequence && p.expressions[0] === node) || } else if (p instanceof AST_Binary) {
(p.TYPE == "Call" && p.expression === node ) || if (p.left === node) continue;
(p instanceof AST_Dot && p.expression === node ) || } else if (p instanceof AST_Conditional) {
(p instanceof AST_Sub && p.expression === node ) || if (p.condition === node) continue;
(p instanceof AST_Conditional && p.condition === node ) || } else if (p instanceof AST_PropAccess) {
(p instanceof AST_Binary && p.left === node ) || if (p.expression === node) continue;
(p instanceof AST_UnaryPostfix && p.expression === node )) } else if (p instanceof AST_Sequence) {
{ if (p.expressions[0] === node) continue;
node = p; } else if (p instanceof AST_Statement) {
} else { return p.body === node;
} else if (p instanceof AST_UnaryPostfix) {
if (p.expression === node) continue;
}
return false; return false;
} }
}
} }

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.3.20", "version": "3.9.1",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -23,16 +23,14 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.15.0", "commander": "~2.20.3"
"source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.5.3", "acorn": "~7.1.0",
"mocha": "~3.5.1", "semver": "~6.3.0"
"semver": "~5.5.0"
}, },
"scripts": { "scripts": {
"test": "node test/run-tests.js" "test": "node test/compress.js && node test/mocha.js"
}, },
"keywords": [ "keywords": [
"cli", "cli",

View File

@@ -5,23 +5,22 @@
var createHash = require("crypto").createHash; var createHash = require("crypto").createHash;
var fetch = require("./fetch"); var fetch = require("./fetch");
var fork = require("child_process").fork; var spawn = require("child_process").spawn;
var zlib = require("zlib"); var zlib = require("zlib");
var args = process.argv.slice(2); var args = process.argv.slice(2);
if (!args.length) { args.unshift("bin/uglifyjs");
args.push("-mc"); if (!args.length) args.push("-mc");
}
args.push("--timings"); args.push("--timings");
var urls = [ var urls = [
"https://code.jquery.com/jquery-3.2.1.js", "https://code.jquery.com/jquery-3.4.1.js",
"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js", "https://code.angularjs.org/1.7.8/angular.js",
"https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js", "https://unpkg.com/mathjs@6.2.3/dist/math.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://unpkg.com/react@15.3.2/dist/react.js", "https://unpkg.com/react@15.3.2/dist/react.js",
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js", "https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.js",
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js", "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js",
"https://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.js", "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js",
"https://raw.githubusercontent.com/kangax/html-minifier/v4.0.0/dist/htmlminifier.js",
]; ];
var results = {}; var results = {};
var remaining = 2 * urls.length; var remaining = 2 * urls.length;
@@ -70,18 +69,20 @@ urls.forEach(function(url) {
}; };
fetch(url, function(err, res) { fetch(url, function(err, res) {
if (err) throw err; if (err) throw err;
var uglifyjs = fork("bin/uglifyjs", args, { silent: true }); var uglifyjs = spawn(process.argv[0], args, { silent: true });
res.on("data", function(data) { res.on("data", function(data) {
results[url].input += data.length; results[url].input += data.length;
}).pipe(uglifyjs.stdin); }).pipe(uglifyjs.stdin);
var sha1 = createHash("sha1");
uglifyjs.stdout.on("data", function(data) { uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length; results[url].output += data.length;
}).pipe(zlib.createGzip({ }).pipe(zlib.createGzip({
level: zlib.Z_BEST_COMPRESSION level: zlib.Z_BEST_COMPRESSION
})).on("data", function(data) { })).on("data", function(data) {
results[url].gzip += data.length; results[url].gzip += data.length;
}).pipe(createHash("sha1")).on("data", function(data) { sha1.update(data);
results[url].sha1 = data.toString("hex"); }).on("end", function() {
results[url].sha1 = sha1.digest("hex");
done(); done();
}); });
uglifyjs.stderr.setEncoding("utf8"); uglifyjs.stderr.setEncoding("utf8");

458
test/compress.js Normal file
View File

@@ -0,0 +1,458 @@
"use strict";
require("../tools/exit");
var assert = require("assert");
var child_process = require("child_process");
var fs = require("fs");
var path = require("path");
var sandbox = require("./sandbox");
var semver = require("semver");
var U = require("./node");
var file = process.argv[2];
var dir = path.resolve(path.dirname(module.filename), "compress");
if (file) {
var minify_options = require("./ufuzz/options.json").map(JSON.stringify);
log("--- {file}", { file: file });
var tests = parse_test(path.resolve(dir, file));
process.exit(Object.keys(tests).filter(function(name) {
return !test_case(tests[name]);
}).length);
} else {
var files = fs.readdirSync(dir).filter(function(name) {
return /\.js$/i.test(name);
});
var failures = 0;
var failed_files = Object.create(null);
(function next() {
var file = files.shift();
if (file) {
child_process.spawn(process.argv[0], [ process.argv[1], file ], {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
if (code) {
failures += code;
failed_files[file] = code;
}
next();
});
} else if (failures) {
console.error();
console.error("!!! Failed " + failures + " test case(s).");
console.error("!!! " + Object.keys(failed_files).join(", "));
process.exit(1);
}
})();
}
function evaluate(code) {
if (code instanceof U.AST_Node) code = make_code(code, { beautify: true });
return new Function("return(" + code + ")")();
}
function log() {
console.log("%s", tmpl.apply(null, arguments));
}
function make_code(ast, options) {
var stream = U.OutputStream(options);
ast.print(stream);
return stream.get();
}
function parse_test(file) {
var script = fs.readFileSync(file, "utf8");
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
try {
var ast = U.parse(script, {
filename: file
});
} catch (e) {
console.error("Caught error while parsing tests in " + file);
console.error(e);
process.exit(1);
}
var tests = Object.create(null);
var tw = new U.TreeWalker(function(node, descend) {
if (node instanceof U.AST_LabeledStatement
&& tw.parent() instanceof U.AST_Toplevel) {
var name = node.label.name;
if (name in tests) {
throw new Error('Duplicated test name "' + name + '" in ' + file);
}
tests[name] = get_one_test(name, node.body);
return true;
}
if (!(node instanceof U.AST_Toplevel)) croak(node);
});
ast.walk(tw);
return tests;
function croak(node) {
throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
file: file,
line: node.start.line,
col: node.start.col,
code: make_code(node, { beautify: false })
}));
}
function read_string(stat) {
if (stat.TYPE == "SimpleStatement") {
var body = stat.body;
switch(body.TYPE) {
case "String":
return body.value;
case "Array":
return body.elements.map(function(element) {
if (element.TYPE !== "String")
throw new Error("Should be array of strings");
return element.value;
}).join("\n");
}
}
throw new Error("Should be string or array of strings");
}
function get_one_test(name, block) {
var test = { name: name, options: {} };
var tw = new U.TreeWalker(function(node, descend) {
if (node instanceof U.AST_Assign) {
if (!(node.left instanceof U.AST_SymbolRef)) {
croak(node);
}
var name = node.left.name;
test[name] = evaluate(node.right);
return true;
}
if (node instanceof U.AST_LabeledStatement) {
var label = node.label;
assert.ok([
"input",
"expect",
"expect_exact",
"expect_warnings",
"expect_stdout",
"node_version",
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
name: label.name,
line: label.start.line,
col: label.start.col
}));
var stat = node.body;
if (label.name == "expect_exact" || label.name == "node_version") {
test[label.name] = read_string(stat);
} else if (label.name == "expect_stdout") {
var body = stat.body;
if (body instanceof U.AST_Boolean) {
test[label.name] = body.value;
} else if (body instanceof U.AST_Call) {
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
}));
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
}));
return node.value;
}));
} else {
test[label.name] = read_string(stat) + "\n";
}
} else {
test[label.name] = stat;
}
return true;
}
});
block.walk(tw);
return test;
}
}
// Try to reminify original input with standard options
// to see if it matches expect_stdout.
function reminify(orig_options, input_code, input_formatted, stdout) {
for (var i = 0; i < minify_options.length; i++) {
var options = JSON.parse(minify_options[i]);
if (options.compress) [
"keep_fargs",
"keep_fnames",
].forEach(function(name) {
if (name in orig_options) {
options.compress[name] = orig_options[name];
}
});
var options_formatted = JSON.stringify(options, null, 4);
var result = U.minify(input_code, options);
if (result.error) {
log([
"!!! failed input reminify",
"---INPUT---",
"{input}",
"---OPTIONS---",
"{options}",
"--ERROR---",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted,
options: options_formatted,
error: result.error,
});
return false;
} else {
var toplevel = sandbox.has_toplevel(options);
var expected = stdout[toplevel ? 1 : 0];
var actual = run_code(result.code, toplevel);
if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
actual = expected;
}
if (!sandbox.same_stdout(expected, actual)) {
log([
"!!! failed running reminified input",
"---INPUT---",
"{input}",
"---OPTIONS---",
"{options}",
"---OUTPUT---",
"{output}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted,
options: options_formatted,
output: result.code,
expected_type: typeof expected == "string" ? "STDOUT" : "ERROR",
expected: expected,
actual_type: typeof actual == "string" ? "STDOUT" : "ERROR",
actual: actual,
});
return false;
}
}
}
return true;
}
function run_code(code, toplevel) {
var result = sandbox.run_code(code, toplevel);
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
}
function test_case(test) {
log(" Running test [{name}]", { name: test.name });
var output_options = test.beautify || {};
var expect;
if (test.expect) {
expect = make_code(to_toplevel(test.expect, test.mangle), output_options);
} else {
expect = test.expect_exact;
}
var input = to_toplevel(test.input, test.mangle);
var input_code = make_code(input);
var input_formatted = make_code(test.input, {
beautify: true,
comments: "all",
keep_quoted_props: true,
quote_style: 3,
});
try {
U.parse(input_code);
} catch (ex) {
log([
"!!! Cannot parse input",
"---INPUT---",
"{input}",
"--PARSE ERROR--",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted,
error: ex,
});
return false;
}
var warnings_emitted = [];
if (test.expect_warnings) {
var expected_warnings = make_code(test.expect_warnings, {
beautify: false,
quote_style: 2, // force double quote to match JSON
});
U.AST_Node.log_function(function(text) {
warnings_emitted.push(text);
}, /"INFO: /.test(expected_warnings));
}
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var 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);
}
if (test.rename) {
input.figure_out_scope(test.mangle);
input.expand_names(test.mangle);
}
var cmp = new U.Compressor(test.options, true);
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (test.mangle.properties) {
output = U.mangle_properties(output, test.mangle.properties);
}
}
output = make_code(output, output_options);
if (expect != output) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---OUTPUT---",
"{output}",
"---EXPECTED---",
"{expected}",
"",
"",
].join("\n"), {
input: input_formatted,
output: output,
expected: expect
});
return false;
}
// expect == output
try {
U.parse(output);
} catch (ex) {
log([
"!!! Test matched expected result but cannot parse output",
"---INPUT---",
"{input}",
"---OUTPUT---",
"{output}",
"--REPARSE ERROR--",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted,
output: output,
error: ex,
});
return false;
}
if (test.expect_warnings) {
warnings_emitted = warnings_emitted.map(function(input) {
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
});
var actual_warnings = JSON.stringify(warnings_emitted);
if (expected_warnings != actual_warnings) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---EXPECTED WARNINGS---",
"{expected_warnings}",
"---ACTUAL WARNINGS---",
"{actual_warnings}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_warnings: expected_warnings,
actual_warnings: actual_warnings,
});
return false;
}
}
if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = [ run_code(input_code), run_code(input_code, true) ];
var toplevel = sandbox.has_toplevel({
compress: test.options,
mangle: test.mangle
});
var actual = stdout[toplevel ? 1 : 0];
if (test.expect_stdout === true) {
test.expect_stdout = actual;
}
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
log([
"!!! Invalid input or expected stdout",
"---INPUT---",
"{input}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof actual == "string" ? "STDOUT" : "ERROR",
actual: actual,
});
return false;
}
actual = run_code(output, toplevel);
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof actual == "string" ? "STDOUT" : "ERROR",
actual: actual,
});
return false;
}
if (!reminify(test.options, input_code, input_formatted, stdout)) {
return false;
}
}
return true;
}
function tmpl() {
return U.string_template.apply(null, arguments);
}
function to_toplevel(input, mangle_options) {
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) {
if (U.push_uniq(tokens, node.start)) node.start.line -= offset;
if (!directive || 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;
}
})));
toplevel.figure_out_scope(mangle_options);
return toplevel;
}

View File

@@ -5,7 +5,8 @@ replace_index: {
properties: true, properties: true,
} }
input: { input: {
console.log(arguments && arguments[0]); var arguments = [];
console.log(arguments[0]);
(function() { (function() {
console.log(arguments[1], arguments["1"], arguments["foo"]); console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42); })("bar", 42);
@@ -21,7 +22,8 @@ replace_index: {
})("bar", 42); })("bar", 42);
} }
expect: { expect: {
console.log(arguments && arguments[0]); var arguments = [];
console.log(arguments[0]);
(function() { (function() {
console.log(arguments[1], arguments[1], arguments.foo); console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42); })("bar", 42);
@@ -45,6 +47,37 @@ replace_index: {
] ]
} }
replace_index_strict: {
options = {
arguments: true,
evaluate: true,
properties: true,
reduce_vars: true,
}
input: {
"use strict";
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
"use strict";
(function() {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
}
expect_stdout: [
"42 42 undefined",
"42 42 undefined",
]
}
replace_index_keep_fargs: { replace_index_keep_fargs: {
options = { options = {
arguments: true, arguments: true,
@@ -53,7 +86,8 @@ replace_index_keep_fargs: {
properties: true, properties: true,
} }
input: { input: {
console.log(arguments && arguments[0]); var arguments = [];
console.log(arguments[0]);
(function() { (function() {
console.log(arguments[1], arguments["1"], arguments["foo"]); console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42); })("bar", 42);
@@ -69,7 +103,8 @@ replace_index_keep_fargs: {
})("bar", 42); })("bar", 42);
} }
expect: { expect: {
console.log(arguments && arguments[0]); var arguments = [];
console.log(arguments[0]);
(function(argument_0, argument_1) { (function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo); console.log(argument_1, argument_1, arguments.foo);
})("bar", 42); })("bar", 42);
@@ -93,6 +128,38 @@ replace_index_keep_fargs: {
] ]
} }
replace_index_keep_fargs_strict: {
options = {
arguments: true,
evaluate: true,
keep_fargs: false,
properties: true,
reduce_vars: true,
}
input: {
"use strict";
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
"use strict";
(function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
}
expect_stdout: [
"42 42 undefined",
"42 42 undefined",
]
}
modified: { modified: {
options = { options = {
arguments: true, arguments: true,
@@ -101,8 +168,10 @@ modified: {
(function(a, b) { (function(a, b) {
var c = arguments[0]; var c = arguments[0];
var d = arguments[1]; var d = arguments[1];
a = "foo"; var a = "foo";
b++; b++;
arguments[0] = "moo";
arguments[1] *= 2;
console.log(a, b, c, d, arguments[0], arguments[1]); console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42); })("bar", 42);
} }
@@ -110,10 +179,600 @@ modified: {
(function(a, b) { (function(a, b) {
var c = a; var c = a;
var d = b; var d = b;
a = "foo"; var a = "foo";
b++; b++;
a = "moo";
b *= 2;
console.log(a, b, c, d, a, b); console.log(a, b, c, d, a, b);
})("bar", 42); })("bar", 42);
} }
expect_stdout: "foo 43 bar 42 foo 43" expect_stdout: "moo 86 bar 42 moo 86"
}
modified_strict: {
options = {
arguments: true,
reduce_vars: true,
}
input: {
"use strict";
(function(a, b) {
var c = arguments[0];
var d = arguments[1];
var a = "foo";
b++;
arguments[0] = "moo";
arguments[1] *= 2;
console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42);
}
expect: {
"use strict";
(function(a, b) {
var c = arguments[0];
var d = arguments[1];
var a = "foo";
b++;
arguments[0] = "moo";
arguments[1] *= 2;
console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42);
}
expect_stdout: "foo 43 bar 42 moo 84"
}
duplicate_argname: {
options = {
arguments: true,
}
input: {
(function(a, b, a) {
console.log(a, b, arguments[0], arguments[1], arguments[2]);
})("foo", 42, "bar");
}
expect: {
(function(a, b, a) {
console.log(a, b, arguments[0], b, a);
})("foo", 42, "bar");
}
expect_stdout: "bar 42 foo 42 bar"
}
issue_3273: {
options = {
arguments: true,
}
input: {
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
function f(a) {
console.log(a, a);
a++;
console.log(a, a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 1",
]
}
issue_3273_reduce_vars: {
options = {
arguments: true,
reduce_vars: true,
}
input: {
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
function f(a) {
console.log(a, a);
a++;
console.log(a, a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 1",
]
}
issue_3273_local_strict: {
options = {
arguments: true,
}
input: {
function f(a) {
"use strict";
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
function f(a) {
"use strict";
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 0",
]
}
issue_3273_local_strict_reduce_vars: {
options = {
arguments: true,
reduce_vars: true,
}
input: {
function f(a) {
"use strict";
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
function f(a) {
"use strict";
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 0",
]
}
issue_3273_global_strict: {
options = {
arguments: true,
}
input: {
"use strict";
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
"use strict";
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 0",
]
}
issue_3273_global_strict_reduce_vars: {
options = {
arguments: true,
reduce_vars: true,
}
input: {
"use strict";
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect: {
"use strict";
function f(a) {
console.log(arguments[0], a);
arguments[0]++;
console.log(arguments[0], a);
}
f(0);
}
expect_stdout: [
"0 0",
"1 0",
]
}
issue_3273_keep_fargs_false: {
options = {
arguments: true,
keep_fargs: false,
reduce_vars: true,
}
input: {
(function() {
"use strict";
arguments[0]++;
console.log(arguments[0]);
})(0);
}
expect: {
(function(argument_0) {
"use strict";
argument_0++;
console.log(argument_0);
})(0);
}
expect_stdout: "1"
}
issue_3273_keep_fargs_strict: {
options = {
arguments: true,
keep_fargs: "strict",
reduce_vars: true,
}
input: {
(function() {
"use strict";
arguments[0]++;
console.log(arguments[0]);
})(0);
}
expect: {
(function(argument_0) {
"use strict";
argument_0++;
console.log(argument_0);
})(0);
}
expect_stdout: "1"
}
issue_3282_1: {
options = {
arguments: true,
reduce_funcs: true,
reduce_vars: true,
keep_fargs: false,
unused: true,
}
input: {
(function(t) {
return function() {
t();
};
})(function() {
'use strict';
function e() {
return arguments[0];
}
e();
e();
})();
}
expect: {
(function() {
return function() {
(function() {
"use strict";
function e() {
return arguments[0];
}
e();
e();
})();
};
})()();
}
expect_stdout: true
}
issue_3282_1_passes: {
options = {
arguments: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
keep_fargs: false,
unused: true,
}
input: {
(function(t) {
return function() {
t();
};
})(function() {
'use strict';
function e() {
return arguments[0];
}
e();
e();
})();
}
expect: {
(function() {
return function() {
(function() {
"use strict";
function e(argument_0) {
return argument_0;
}
e();
e();
})();
};
})()();
}
expect_stdout: true
}
issue_3282_2: {
options = {
arguments: true,
reduce_vars: true,
keep_fargs: false,
unused: true,
}
input: {
(function(f) {
f();
})(function() {
return (function(t) {
return function() {
t();
};
})(function() {
'use strict';
function e() {
return arguments[0];
}
e();
e();
})();
});
}
expect: {
(function() {
(function() {
return function(t) {
return function() {
t();
};
}(function() {
"use strict";
function e() {
return arguments[0];
}
e();
e();
})();
})();
})();
}
expect_stdout: true
}
issue_3282_2_passes: {
options = {
arguments: true,
passes: 2,
reduce_vars: true,
keep_fargs: false,
unused: true,
}
input: {
(function(f) {
f();
})(function() {
return (function(t) {
return function() {
t();
};
})(function() {
'use strict';
function e() {
return arguments[0];
}
e();
e();
})();
});
}
expect: {
(function() {
(function() {
return function(t) {
return function() {
t();
};
}(function() {
"use strict";
function e(argument_0) {
return argument_0;
}
e();
e();
})();
})();
})();
}
expect_stdout: true
}
issue_3420_1: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(function() {
return function() {
return arguments[0];
};
}().length);
}
expect: {
console.log(function() {
return function() {
return arguments[0];
};
}().length);
}
expect_stdout: "0"
}
issue_3420_2: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
var foo = function() {
delete arguments[0];
};
foo();
}
expect: {
var foo = function() {
delete arguments[0];
};
foo();
}
expect_stdout: true
}
issue_3420_3: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
var foo = function() {
delete arguments[0];
};
foo();
}
expect: {
"use strict";
var foo = function() {
delete arguments[0];
};
foo();
}
expect_stdout: true
}
issue_3420_4: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
!function() {
console.log(arguments[0]);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect: {
!function(argument_0) {
console.log(argument_0);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect_stdout: [
"42",
"undefined",
]
}
issue_3420_5: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
!function() {
console.log(arguments[0]);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect: {
"use strict";
!function(argument_0) {
console.log(argument_0);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect_stdout: [
"42",
"undefined",
]
}
issue_3420_6: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(function() {
return delete arguments[0];
}());
}
expect: {
console.log(function() {
return delete arguments[0];
}());
}
expect_stdout: "true"
}
issue_3420_7: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
console.log(function() {
return delete arguments[0];
}());
}
expect: {
"use strict";
console.log(function() {
return delete arguments[0];
}());
}
expect_stdout: "true"
} }

View File

@@ -15,9 +15,10 @@ holes_and_undefined: {
constant_join: { constant_join: {
options = { options = {
unsafe : true, evaluate: true,
evaluate : true strings: true,
}; unsafe: true,
}
input: { input: {
var a = [ "foo", "bar", "baz" ].join(""); var a = [ "foo", "bar", "baz" ].join("");
var a1 = [ "foo", "bar", "baz" ].join(); var a1 = [ "foo", "bar", "baz" ].join();
@@ -64,9 +65,10 @@ constant_join: {
constant_join_2: { constant_join_2: {
options = { options = {
unsafe : true, evaluate: true,
evaluate : true strings: true,
}; unsafe: true,
}
input: { input: {
var a = [ "foo", "bar", boo(), "baz", "x", "y" ].join(""); var a = [ "foo", "bar", boo(), "baz", "x", "y" ].join("");
var b = [ "foo", "bar", boo(), "baz", "x", "y" ].join("-"); var b = [ "foo", "bar", boo(), "baz", "x", "y" ].join("-");
@@ -93,10 +95,12 @@ constant_join_2: {
constant_join_3: { constant_join_3: {
options = { options = {
unsafe: true,
evaluate: true, evaluate: true,
}; strings: true,
unsafe: true,
}
input: { input: {
var foo, bar, baz;
var a = [ null ].join(); var a = [ null ].join();
var b = [ , ].join(); var b = [ , ].join();
var c = [ , 1, , 3 ].join(); var c = [ , 1, , 3 ].join();
@@ -111,6 +115,7 @@ constant_join_3: {
var l = [ foo, bar + "baz" ].join(""); var l = [ foo, bar + "baz" ].join("");
} }
expect: { expect: {
var foo, bar, baz;
var a = ""; var a = "";
var b = ""; var b = "";
var c = ",1,,3"; var c = ",1,,3";
@@ -133,7 +138,7 @@ for_loop: {
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
unused: true, unused: true,
}; }
input: { input: {
function f0() { function f0() {
var a = [1, 2, 3]; var a = [1, 2, 3];
@@ -239,3 +244,113 @@ index_length: {
} }
expect_stdout: "1 2" expect_stdout: "1 2"
} }
constructor_bad: {
options = {
unsafe: true
}
input: {
try {
Array(NaN);
console.log("FAIL1");
} catch (ex) {
try {
new Array(NaN);
console.log("FAIL2");
} catch (ex) {
console.log("PASS");
}
}
try {
Array(3.14);
console.log("FAIL1");
} catch (ex) {
try {
new Array(3.14);
console.log("FAIL2");
} catch (ex) {
console.log("PASS");
}
}
}
expect: {
try {
Array(NaN);
console.log("FAIL1");
} catch (ex) {
try {
Array(NaN);
console.log("FAIL2");
} catch (ex) {
console.log("PASS");
}
}
try {
Array(3.14);
console.log("FAIL1");
} catch (ex) {
try {
Array(3.14);
console.log("FAIL2");
} catch (ex) {
console.log("PASS");
}
}
}
expect_stdout: [
"PASS",
"PASS",
]
expect_warnings: [
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:13,12]",
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:17,16]",
]
}
constructor_good: {
options = {
unsafe: true
}
input: {
console.log(Array());
console.log(Array(0));
console.log(Array(1));
console.log(Array(6));
console.log(Array(7));
console.log(Array(1, 2));
console.log(Array(false));
console.log(Array("foo"));
console.log(Array(Array));
console.log(new Array());
console.log(new Array(0));
console.log(new Array(1));
console.log(new Array(6));
console.log(new Array(7));
console.log(new Array(1, 2));
console.log(new Array(false));
console.log(new Array("foo"));
console.log(new Array(Array));
}
expect: {
console.log([]);
console.log([]);
console.log([,]);
console.log([,,,,,,]);
console.log(Array(7));
console.log([ 1, 2 ]);
console.log([ false ]);
console.log([ "foo" ]);
console.log(Array(Array));
console.log([]);
console.log([]);
console.log([,]);
console.log([,,,,,,]);
console.log(Array(7));
console.log([ 1, 2 ]);
console.log([ false ]);
console.log([ "foo" ]);
console.log(Array(Array));
}
expect_stdout: true
expect_warnings: []
}

View File

@@ -1,24 +1,25 @@
asm_mixed: { asm_mixed: {
options = { options = {
sequences : true, assignments: true,
properties : true, booleans: true,
dead_code : true, comparisons: true,
drop_debugger : true, conditionals: true,
conditionals : true, dead_code: true,
comparisons : true, drop_debugger: true,
evaluate : true, evaluate: true,
booleans : true, hoist_funs: true,
loops : true, hoist_vars: true,
unused : true, if_return: true,
hoist_funs : true, join_vars: true,
keep_fargs : true, keep_fargs: true,
keep_fnames : false, keep_fnames: false,
hoist_vars : true, loops: true,
if_return : true, negate_iife: true,
join_vars : true, properties: true,
side_effects : true, sequences: true,
negate_iife : true side_effects: true,
}; unused: true,
}
input: { input: {
// adapted from http://asmjs.org/spec/latest/ // adapted from http://asmjs.org/spec/latest/
function asm_GeometricMean(stdlib, foreign, buffer) { function asm_GeometricMean(stdlib, foreign, buffer) {
@@ -95,7 +96,7 @@ asm_mixed: {
return +sum; return +sum;
} }
function geometricMean(start, end) { function geometricMean(start, end) {
return start |= 0, end |= 0, +exp(+logSum(start, end) / +(end - start | 0)); return start |= 0, end |= 0, +exp(logSum(start, end) / (end - start | 0));
} }
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer); var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
return { geometricMean: geometricMean }; return { geometricMean: geometricMean };
@@ -165,3 +166,69 @@ asm_nested_functions: {
} }
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;' expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
} }
issue_3636_1: {
mangle = {}
input: {
function n(stdlib, foreign, buffer) {
"use asm";
function add(x, y) {
x = x | 0;
y = y | 0;
return x + y | 0;
}
return {
add: add
};
}
console.log(new n().add("foo", 42));
}
expect: {
function n(o, e, u) {
"use asm";
function d(n, o) {
n = n | 0;
o = o | 0;
return n + o | 0;
}
return {
add: d
};
}
console.log(new n().add("foo", 42));
}
expect_stdout: "42"
}
issue_3636_2: {
mangle = {}
input: {
var n = function(stdlib, foreign, buffer) {
"use asm";
function add(x, y) {
x = x | 0;
y = y | 0;
return x + y | 0;
}
return {
add: add
};
};
console.log(new n().add("foo", 42));
}
expect: {
var n = function(n, o, e) {
"use asm";
function r(n, o) {
n = n | 0;
o = o | 0;
return n + o | 0;
}
return {
add: r
};
};
console.log(new n().add("foo", 42));
}
expect_stdout: "42"
}

View File

@@ -1,5 +1,6 @@
op_equals_left_local_var: { op_equals_left_local_var: {
options = { options = {
assignments: true,
evaluate: true, evaluate: true,
} }
input: { input: {
@@ -60,6 +61,7 @@ op_equals_left_local_var: {
op_equals_right_local_var: { op_equals_right_local_var: {
options = { options = {
assignments: true,
evaluate: true, evaluate: true,
} }
input: { input: {
@@ -123,6 +125,7 @@ op_equals_right_local_var: {
} }
op_equals_left_global_var: { op_equals_left_global_var: {
options = { options = {
assignments: true,
evaluate: true, evaluate: true,
} }
input: { input: {
@@ -179,6 +182,7 @@ op_equals_left_global_var: {
op_equals_right_global_var: { op_equals_right_global_var: {
options = { options = {
assignments: true,
evaluate: true, evaluate: true,
} }
input: { input: {
@@ -236,3 +240,170 @@ op_equals_right_global_var: {
x = g() & x; x = g() & x;
} }
} }
increment_decrement_1: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
a += 1;
a -= 1;
return a;
}(42));
}
expect: {
console.log(function(a){
++a;
--a;
return a;
}(42));
}
expect_stdout: "42"
}
increment_decrement_2: {
options = {
assignments: true,
passes: 2,
reduce_vars: true,
}
input: {
console.log(function(a) {
a = a + 1;
a = a - 1;
a += 1;
a -= 1;
return a;
}(42));
}
expect: {
console.log(function(a){
++a;
--a;
++a;
--a;
return a;
}(42));
}
expect_stdout: "42"
}
issue_3375_1: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect: {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect_stdout: "string object1"
}
issue_3375_2: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = b -= 1;
--b;
return a;
}("object"));
}
expect: {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = --b;
--b;
return a;
}("object"));
}
expect_stdout: "number NaN"
}
issue_3427: {
options = {
assignments: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a;
a || (a = {});
})();
}
expect: {}
}
issue_3429_1: {
options = {
assignments: true,
side_effects: true,
unused: true,
}
input: {
var a = "PASS";
(function(b) {
b && (b = a = "FAIL");
})();
console.log(a);
}
expect: {
var a = "PASS";
(function(b) {
b = b && (a = "FAIL");
})();
console.log(a);
}
expect_stdout: "PASS"
}
issue_3429_2: {
options = {
assignments: true,
side_effects: true,
unused: true,
}
input: {
var a;
(function(b) {
b || (b = a = "FAIL");
})(42);
console.log(a);
}
expect: {
var a;
(function(b) {
b = b || (a = "FAIL");
})(42);
console.log(a);
}
expect_stdout: "undefined"
}

155
test/compress/booleans.js Normal file
View File

@@ -0,0 +1,155 @@
iife_boolean_context: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(function() {
return Object(1) || false;
}() ? "PASS" : "FAIL");
console.log(function() {
return [].length || true;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function() {
return Object(1);
}() ? "PASS" : "FAIL");
console.log(function() {
return [].length, 1;
}() ? "PASS" : "FAIL");
}
expect_stdout: [
"PASS",
"PASS",
]
expect_warnings: [
"WARN: Dropping side-effect-free || [test/compress/booleans.js:2,19]",
"WARN: Boolean || always true [test/compress/booleans.js:5,19]",
]
}
issue_3465_1: {
options = {
booleans: true,
}
input: {
console.log(function(a) {
return typeof a;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
return 1;
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_3465_2: {
options = {
booleans: true,
}
input: {
console.log(function f(a) {
if (!a) console.log(f(42));
return typeof a;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function f(a) {
if (!a) console.log(f(42));
return typeof a;
}() ? "PASS" : "FAIL");
}
expect_stdout: [
"number",
"PASS",
]
}
issue_3465_3: {
options = {
booleans: true,
passes: 2,
unused: true,
}
input: {
console.log(function f(a) {
return typeof a;
}() ? "PASS" : "FAIL");
}
expect: {
console.log(function(a) {
return 1;
}() ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
issue_2737_2: {
options = {
booleans: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
(function(bar) {
for (;bar();) break;
})(function qux() {
return console.log("PASS"), qux;
});
}
expect: {
(function(bar) {
for (;bar();) break;
})(function() {
return console.log("PASS"), 1;
});
}
expect_stdout: "PASS"
}
issue_3658: {
options = {
booleans: true,
evaluate: true,
reduce_vars: true,
}
input: {
console.log(function f() {
console || f();
return "PASS";
}());
}
expect: {
console.log(function f() {
console || f();
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_3690: {
options = {
booleans: true,
unused: true,
}
input: {
console.log(function(a) {
return function() {
return a = [ this ];
}() ? "PASS" : "FAIL";
}());
}
expect: {
console.log(function(a) {
return function() {
return 1;
}() ? "PASS" : "FAIL";
}());
}
expect_stdout: "PASS"
}

File diff suppressed because it is too large Load Diff

View File

@@ -33,10 +33,10 @@ unsafe_comps: {
} }
expect: { expect: {
var obj1, obj2; var obj1, obj2;
obj2 < obj1 ? g1() : f1(); (obj2 < obj1 ? g1 : f1)();
obj1 < obj2 ? f2() : g2(); (obj1 < obj2 ? f2 : g2)();
obj1 < obj2 ? g3() : f3(); (obj1 < obj2 ? g3 : f3)();
obj2 < obj1 ? f4() : g4(); (obj2 < obj1 ? f4 : g4)();
} }
} }
@@ -295,3 +295,148 @@ issue_2857_6: {
} }
expect_stdout: "true" expect_stdout: "true"
} }
is_boolean_unsafe: {
options = {
comparisons: true,
unsafe: true,
}
input: {
console.log(/foo/.test("bar") === [].isPrototypeOf({}));
}
expect: {
console.log(/foo/.test("bar") == [].isPrototypeOf({}));
}
expect_stdout: "true"
}
is_number_unsafe: {
options = {
comparisons: true,
unsafe: true,
}
input: {
console.log(Math.acos(42) !== "foo".charCodeAt(4));
}
expect: {
console.log(Math.acos(42) != "foo".charCodeAt(4));
}
expect_stdout: "true"
}
is_boolean_var: {
options = {
comparisons: true,
reduce_vars: true,
}
input: {
console.log(function(a, b) {
for (var i = 0, c = !b; i < a.length; i++)
if (!a[i] === c)
return i;
}([ false, true ], 42));
}
expect: {
console.log(function(a, b) {
for (var i = 0, c = !b; i < a.length; i++)
if (!a[i] == c)
return i;
}([ false, true ], 42));
}
expect_stdout: "1"
}
is_defined: {
options = {
comparisons: true,
}
input: {
console.log(function a() {
return void 0 === a;
}());
}
expect: {
console.log(function a() {
return a, false;
}());
}
expect_stdout: "false"
expect_warnings: [
"WARN: Expression always defined [test/compress/comparisons.js:2,19]",
]
}
unsafe_indexOf: {
options = {
booleans: true,
comparisons: true,
unsafe: true,
}
input: {
var a = Object.keys({ foo: 42 });
if (a.indexOf("bar") < 0) console.log("PASS");
if (0 > a.indexOf("bar")) console.log("PASS");
if (a.indexOf("foo") >= 0) console.log("PASS");
if (0 <= a.indexOf("foo")) console.log("PASS");
if (a.indexOf("foo") > -1) console.log("PASS");
if (-1 < a.indexOf("foo")) console.log("PASS");
if (a.indexOf("bar") == -1) console.log("PASS");
if (-1 == a.indexOf("bar")) console.log("PASS");
if (a.indexOf("bar") === -1) console.log("PASS");
if (-1 === a.indexOf("bar")) console.log("PASS");
if (a.indexOf("foo") != -1) console.log("PASS");
if (-1 != a.indexOf("foo")) console.log("PASS");
if (a.indexOf("foo") !== -1) console.log("PASS");
if (-1 !== a.indexOf("foo")) console.log("PASS");
}
expect: {
var a = Object.keys({ foo: 42 });
if (!~a.indexOf("bar")) console.log("PASS");
if (!~a.indexOf("bar")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (!~a.indexOf("bar")) console.log("PASS");
if (!~a.indexOf("bar")) console.log("PASS");
if (!~a.indexOf("bar")) console.log("PASS");
if (!~a.indexOf("bar")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
if (~a.indexOf("foo")) console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
]
}
issue_3413: {
options = {
comparisons: true,
evaluate: true,
side_effects: true,
}
input: {
var b;
void 0 !== ("" < b || void 0) || console.log("PASS");
}
expect: {
var b;
void 0 !== ("" < b || void 0) || console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -1,7 +1,7 @@
concat_1: { concat_1: {
options = { options = {
evaluate: true evaluate: true,
}; }
input: { input: {
var a = "foo" + "bar" + x() + "moo" + "foo" + y() + "x" + "y" + "z" + q(); var a = "foo" + "bar" + x() + "moo" + "foo" + y() + "x" + "y" + "z" + q();
var b = "foo" + 1 + x() + 2 + "boo"; var b = "foo" + 1 + x() + 2 + "boo";
@@ -26,7 +26,9 @@ concat_1: {
} }
concat_2: { concat_2: {
options = {}; options = {
strings: true,
}
input: { input: {
console.log( console.log(
1 + (2 + 3), 1 + (2 + 3),
@@ -55,7 +57,9 @@ concat_2: {
} }
concat_3: { concat_3: {
options = {}; options = {
strings: true,
}
input: { input: {
console.log( console.log(
1 + 2 + (3 + 4 + 5), 1 + 2 + (3 + 4 + 5),
@@ -84,7 +88,9 @@ concat_3: {
} }
concat_4: { concat_4: {
options = {}; options = {
strings: true,
}
input: { input: {
console.log( console.log(
1 + "2" + (3 + 4 + 5), 1 + "2" + (3 + 4 + 5),
@@ -113,7 +119,9 @@ concat_4: {
} }
concat_5: { concat_5: {
options = {}; options = {
strings: true,
}
input: { input: {
console.log( console.log(
"1" + 2 + (3 + 4 + 5), "1" + 2 + (3 + 4 + 5),
@@ -142,7 +150,9 @@ concat_5: {
} }
concat_6: { concat_6: {
options = {}; options = {
strings: true,
}
input: { input: {
console.log( console.log(
"1" + "2" + (3 + 4 + 5), "1" + "2" + (3 + 4 + 5),
@@ -171,6 +181,9 @@ concat_6: {
} }
concat_7: { concat_7: {
options = {
strings: true,
}
input: { input: {
console.log( console.log(
"" + 1, "" + 1,
@@ -197,6 +210,9 @@ concat_7: {
} }
concat_8: { concat_8: {
options = {
strings: true,
}
input: { input: {
console.log( console.log(
1 + "", 1 + "",
@@ -221,3 +237,20 @@ concat_8: {
} }
expect_stdout: true expect_stdout: true
} }
issue_3689: {
options = {
strings: true,
}
input: {
console.log(function(a) {
return a + ("" + (a[0] = 0));
}([]));
}
expect: {
console.log(function(a) {
return a + ("" + (a[0] = 0));
}([]));
}
expect_stdout: "00"
}

View File

@@ -1,7 +1,7 @@
ifs_1: { ifs_1: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
if (foo) bar(); if (foo) bar();
if (!foo); else bar(); if (!foo); else bar();
@@ -18,8 +18,8 @@ ifs_1: {
ifs_2: { ifs_2: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
if (foo) { if (foo) {
x(); x();
@@ -41,18 +41,18 @@ ifs_2: {
} }
expect: { expect: {
foo ? x() : bar ? y() : baz && z(); foo ? x() : bar ? y() : baz && z();
foo ? x() : bar ? y() : baz ? z() : t(); (foo ? x : bar ? y : baz ? z : t)();
} }
} }
ifs_3_should_warn: { ifs_3_should_warn: {
options = { options = {
conditionals : true, booleans: true,
dead_code : true, conditionals: true,
evaluate : true, dead_code: true,
booleans : true, evaluate: true,
side_effects : true, side_effects: true,
}; }
input: { input: {
var x, y; var x, y;
if (x && !(x + "1") && y) { // 1 if (x && !(x + "1") && y) { // 1
@@ -78,8 +78,8 @@ ifs_3_should_warn: {
ifs_4: { ifs_4: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
if (foo && bar) { if (foo && bar) {
x(foo)[10].bar.baz = something(); x(foo)[10].bar.baz = something();
@@ -95,10 +95,10 @@ ifs_4: {
ifs_5: { ifs_5: {
options = { options = {
if_return: true,
conditionals: true,
comparisons: true, comparisons: true,
}; conditionals: true,
if_return: true,
}
input: { input: {
function f() { function f() {
if (foo) return; if (foo) return;
@@ -132,9 +132,9 @@ ifs_5: {
ifs_6: { ifs_6: {
options = { options = {
comparisons: true,
conditionals: true, conditionals: true,
comparisons: true }
};
input: { input: {
var x, y; var x, y;
if (!foo && !bar && !baz && !boo) { if (!foo && !bar && !baz && !boo) {
@@ -161,10 +161,28 @@ ifs_6: {
} }
} }
ifs_7: {
options = {
conditionals: true,
}
input: {
if (A); else;
if (A) while (B); else;
if (A); else while (C);
if (A) while (B); else while (C);
}
expect: {
A;
if (A) while (B);
if (!A) while (C);
if (A) while (B); else while (C);
}
}
cond_1: { cond_1: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
function foo(do_something, some_condition) { function foo(do_something, some_condition) {
if (some_condition) { if (some_condition) {
@@ -189,8 +207,8 @@ cond_1: {
cond_2: { cond_2: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
function foo(x, FooBar, some_condition) { function foo(x, FooBar, some_condition) {
if (some_condition) { if (some_condition) {
@@ -209,8 +227,8 @@ cond_2: {
cond_3: { cond_3: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
var FooBar; var FooBar;
if (some_condition()) { if (some_condition()) {
@@ -227,8 +245,8 @@ cond_3: {
cond_4: { cond_4: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
var do_something; var do_something;
if (some_condition()) { if (some_condition()) {
@@ -251,8 +269,8 @@ cond_4: {
cond_5: { cond_5: {
options = { options = {
conditionals: true conditionals: true,
}; }
input: { input: {
if (some_condition()) { if (some_condition()) {
if (some_other_condition()) { if (some_other_condition()) {
@@ -271,17 +289,56 @@ cond_5: {
} }
} }
expect: { expect: {
some_condition() && some_other_condition() ? do_something() : alternate(); (some_condition() && some_other_condition() ? do_something : alternate)();
some_condition() && some_other_condition() && do_something(); some_condition() && some_other_condition() && do_something();
} }
} }
cond_6: {
options = {
booleans: true,
conditionals: true,
}
input: {
x ? a : b;
x ? a : a;
x ? y ? a : b : c;
x ? y ? a : a : b;
x ? y ? a : b : b;
x ? y ? a : b : a;
x ? y ? a : a : a;
x ? a : y ? b : c;
x ? a : y ? a : b;
x ? a : y ? b : b;
x ? a : y ? b : a;
x ? a : y ? a : a;
}
expect: {
x ? a : b;
x, a;
x ? y ? a : b : c;
x ? (y, a) : b;
x && y ? a : b;
!x || y ? a : b;
x && y, a;
x ? a : y ? b : c;
x || y ? a : b;
x ? a : (y, b);
!x && y ? b : a;
!x && y, a;
}
}
cond_7: { cond_7: {
options = { options = {
conditionals: true, conditionals: true,
evaluate : true, evaluate: true,
side_effects: true, side_effects: true,
}; }
input: { input: {
var x, y, z, a, b; var x, y, z, a, b;
// compress these // compress these
@@ -342,8 +399,8 @@ cond_7: {
cond_7_1: { cond_7_1: {
options = { options = {
conditionals: true, conditionals: true,
evaluate : true evaluate: true,
}; }
input: { input: {
var x; var x;
// access to global should be assumed to have side effects // access to global should be assumed to have side effects
@@ -361,10 +418,10 @@ cond_7_1: {
cond_8: { cond_8: {
options = { options = {
booleans: false,
conditionals: true, conditionals: true,
evaluate : true, evaluate: true,
booleans : false }
};
input: { input: {
var a; var a;
// compress these // compress these
@@ -445,10 +502,10 @@ cond_8: {
cond_8b: { cond_8b: {
options = { options = {
booleans: true,
conditionals: true, conditionals: true,
evaluate : true, evaluate: true,
booleans : true }
};
input: { input: {
var a; var a;
// compress these // compress these
@@ -528,10 +585,10 @@ cond_8b: {
cond_8c: { cond_8c: {
options = { options = {
booleans: false,
conditionals: true, conditionals: true,
evaluate : false, evaluate: false,
booleans : false }
};
input: { input: {
var a; var a;
// compress these // compress these
@@ -645,11 +702,104 @@ cond_9: {
} }
} }
cond_10: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f(a) {
if (1 == a) return "foo";
if (2 == a) return "foo";
if (3 == a) return "foo";
if (4 == a) return 42;
if (5 == a) return "foo";
if (6 == a) return "foo";
return "bar";
}
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
}
expect: {
function f(a) {
return 1 == a || 2 == a || 3 == a ? "foo" : 4 == a ? 42 : 5 == a || 6 == a ? "foo" : "bar";
}
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
}
expect_stdout: "foo foo foo 42 foo foo bar"
}
cond_11: {
options = {
conditionals: true,
}
input: {
var o = {
p: "foo",
q: function() {
return this.p;
}
};
function f() {
return "bar";
}
function g(a) {
return a ? f() : o.q();
}
console.log(g(0), g(1));
}
expect: {
var o = {
p: "foo",
q: function() {
return this.p;
}
};
function f() {
return "bar";
}
function g(a) {
return a ? f() : o.q();
}
console.log(g(0), g(1));
}
expect_stdout: "foo bar"
}
cond_12: {
options = {
conditionals: true,
}
input: {
x ? y && a : a;
x ? y || a : a;
x ? a : y && a;
x ? a : y || a;
}
expect: {
(!x || y) && a;
x && y || a;
(x || y) && a;
!x && y || a;
}
}
ternary_boolean_consequent: { ternary_boolean_consequent: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, booleans: true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, collapse_vars: true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
} }
input: { input: {
function f1() { return a == b ? true : x; } function f1() { return a == b ? true : x; }
@@ -675,9 +825,21 @@ ternary_boolean_consequent: {
ternary_boolean_alternative: { ternary_boolean_alternative: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, booleans: true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, collapse_vars: true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
} }
input: { input: {
function f1() { return a == b ? x : true; } function f1() { return a == b ? x : true; }
@@ -778,11 +940,11 @@ trivial_boolean_ternary_expressions : {
issue_1154: { issue_1154: {
options = { options = {
booleans: true,
conditionals: true, conditionals: true,
evaluate : true, evaluate: true,
booleans : true,
side_effects: true, side_effects: true,
}; }
input: { input: {
function f1(x) { return x ? -1 : -1; } function f1(x) { return x ? -1 : -1; }
function f2(x) { return x ? +2 : +2; } function f2(x) { return x ? +2 : +2; }
@@ -818,7 +980,7 @@ issue_1154: {
no_evaluate: { no_evaluate: {
options = { options = {
conditionals: true, conditionals: true,
evaluate : false, evaluate: false,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -1078,11 +1240,11 @@ issue_2535_1: {
expect: { expect: {
y(); y();
x() && y(); x() && y();
(x(), 1) && y(); x(), y();
x() && y(); x() && y();
x() && y(); x() && y();
x() && y(); x() && y();
(x(), 0) && y(); x();
} }
} }
@@ -1268,3 +1430,239 @@ to_and_or: {
} }
expect_stdout: true expect_stdout: true
} }
cond_seq_assign_1: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a) {
var t;
if (a) {
t = "foo";
t = "bar";
} else {
console.log(t);
t = 42;
}
console.log(t);
}
f(f);
f();
}
expect: {
function f(a) {
var t;
t = a ? (t = "foo", "bar") : (console.log(t), 42),
console.log(t);
}
f(f),
f();
}
expect_stdout: [
"bar",
"undefined",
"42",
]
}
cond_seq_assign_2: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a) {
var t;
if (a) {
t = "foo";
a = "bar";
} else {
console.log(t);
t = 42;
}
console.log(t);
}
f(f);
f();
}
expect: {
function f(a) {
var t;
a ? (t = "foo", a = "bar") : (console.log(t), t = 42),
console.log(t);
}
f(f),
f();
}
expect_stdout: [
"foo",
"undefined",
"42",
]
}
cond_seq_assign_3: {
options = {
assignments: true,
conditionals: true,
}
input: {
var c = 0;
if (this)
c = 1 + c, c = c + 1;
else
c = 1 + c, c = c + 1;
console.log(c);
}
expect: {
var c = 0;
this, c = 1 + c, c += 1;
console.log(c);
}
expect_stdout: "2"
}
issue_3271: {
options = {
conditionals: true,
}
input: {
function f(a) {
var i = 0, b = [];
if (a) {
b[i++] = 4,
b[i++] = 1;
} else {
b[i++] = 3,
b[i++] = 2,
b[i++] = 1;
}
return b;
}
console.log(f(0).pop(), f(1).pop());
}
expect: {
function f(a) {
var i = 0, b = [];
a ? b[i++] = 4 : (b[i++] = 3, b[i++] = 2),
b[i++] = 1;
return b;
}
console.log(f(0).pop(), f(1).pop());
}
expect_stdout: "1 1"
}
iife_condition: {
options = {
conditionals: true,
side_effects: true,
}
input: {
if (function() {
return console;
}())
console.log("PASS");
}
expect: {
!function() {
return console;
}() || console.log("PASS");
}
expect_stdout: "PASS"
}
angularjs_chain: {
options = {
conditionals: true,
passes: 2,
side_effects: true,
}
input: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
if (create && create !== 1) {
if (lhs && lhs[right] == null) {
lhs[right] = {};
}
}
var value = lhs != null ? lhs[right] : undefined;
if (context) {
return { context: lhs, name: right, value: value };
} else {
return value;
}
}
}
expect: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
var value = null != lhs ? lhs[right] : void 0;
return context ? {
context: lhs,
name: right,
value: value
} : value;
}
}
}
issue_3576: {
options = {
conditionals: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
}
input: {
var c = "FAIL";
(function(a) {
(a = -1) ? (a && (a.a = 0)) : (a && (a.a = 0));
a && a[c = "PASS"]++;
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function(a) {
a = -1, a, a.a = 0;
a, a[c = "PASS"]++;
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3668: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f() {
try {
var undefined = typeof f;
if (!f) return undefined;
return;
} catch (e) {
return "FAIL";
}
}
console.log(f());
}
expect: {
function f() {
try {
var undefined = typeof f;
return f ? void 0 : undefined;
} catch (e) {
return "FAIL";
}
}
console.log(f());
}
expect_stdout: "undefined"
}

View File

@@ -1,7 +1,7 @@
dead_code_1: { dead_code_1: {
options = { options = {
dead_code: true dead_code: true,
}; }
input: { input: {
function f() { function f() {
a(); a();
@@ -25,8 +25,8 @@ dead_code_1: {
dead_code_2_should_warn: { dead_code_2_should_warn: {
options = { options = {
dead_code: true dead_code: true,
}; }
input: { input: {
function f() { function f() {
g(); g();
@@ -64,13 +64,13 @@ dead_code_2_should_warn: {
dead_code_constant_boolean_should_warn_more: { dead_code_constant_boolean_should_warn_more: {
options = { options = {
dead_code : true, booleans: true,
loops : true, conditionals: true,
booleans : true, dead_code: true,
conditionals : true, evaluate: true,
evaluate : true, loops: true,
side_effects : true, side_effects: true,
}; }
input: { input: {
while (!((foo && bar) || (x + "0"))) { while (!((foo && bar) || (x + "0"))) {
console.log("unreachable"); console.log("unreachable");
@@ -141,207 +141,6 @@ try_catch_finally: {
] ]
} }
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}
collapse_vars_assignment: { collapse_vars_assignment: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -863,23 +662,6 @@ issue_2749: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
unsafe_builtin: {
options = {
side_effects: true,
unsafe: true,
}
input: {
(!w).constructor(x);
Math.abs(y);
[ 1, 2, z ].valueOf();
}
expect: {
w, x;
y;
z;
}
}
issue_2860_1: { issue_2860_1: {
options = { options = {
dead_code: true, dead_code: true,
@@ -892,9 +674,7 @@ issue_2860_1: {
}()); }());
} }
expect: { expect: {
console.log(function(a) { console.log(1);
return 1 ^ a;
}());
} }
expect_stdout: "1" expect_stdout: "1"
} }
@@ -942,3 +722,173 @@ issue_2929: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3402: {
options = {
dead_code: true,
evaluate: true,
functions: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
var f = function f() {
f = 42;
console.log(typeof f);
};
"function" == typeof f && f();
"function" == typeof f && f();
console.log(typeof f);
}
expect: {
function f() {
console.log(typeof f);
}
f();
f();
console.log(typeof f);
}
expect_stdout: [
"function",
"function",
"function",
]
}
issue_3406: {
options = {
dead_code: true,
}
input: {
console.log(function f(a) {
return delete (f = a);
}());
}
expect: {
console.log(function f(a) {
return delete (0, a);
}());
}
expect_stdout: "true"
}
function_assign: {
options = {
dead_code: true,
}
input: {
console.log(function() {
var a = "PASS";
function h(c) {
return c;
}
h.p = function(b) {
return b;
}.p = a;
return h;
}().p);
}
expect: {
console.log(function() {
var a = "PASS";
function h(c) {
return c;
}
h.p = a;
return h;
}().p);
}
expect_stdout: "PASS"
}
issue_3552: {
options = {
dead_code: true,
pure_getters: "strict",
}
input: {
var a = "PASS";
(function() {
(1..p += 42) && (a = "FAIL");
})();
console.log(a);
}
expect: {
var a = "PASS";
(function() {
(1..p += 42) && (a = "FAIL");
})();
console.log(a);
}
expect_stdout: "PASS"
}
unreachable_assign: {
options = {
dead_code: true,
strings: true,
}
input: {
console.log(A = "P" + (A = "A" + (B = "S" + (A = B = "S"))), A, B);
}
expect: {
console.log(A = "P" + "A" + (B = "S" + "S"), A, B);
}
expect_stdout: "PASS PASS SS"
}
catch_return_assign: {
options = {
dead_code: true,
}
input: {
console.log(function() {
try {
throw "FAIL";
} catch (e) {
return e = "PASS";
}
}());
}
expect: {
console.log(function() {
try {
throw "FAIL";
} catch (e) {
return "PASS";
}
}());
}
expect_stdout: "PASS"
}
issue_3578: {
options = {
dead_code: true,
}
input: {
var a = "FAIL", b, c;
try {
b = c.p = b = 0;
} catch (e) {
b += 42;
b && (a = "PASS");
}
console.log(a);
}
expect: {
var a = "FAIL", b, c;
try {
b = c.p = b = 0;
} catch (e) {
b += 42;
b && (a = "PASS");
}
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -1,7 +1,7 @@
keep_debugger: { keep_debugger: {
options = { options = {
drop_debugger: false drop_debugger: false,
}; }
input: { input: {
debugger; debugger;
} }
@@ -12,8 +12,8 @@ keep_debugger: {
drop_debugger: { drop_debugger: {
options = { options = {
drop_debugger: true drop_debugger: true,
}; }
input: { input: {
debugger; debugger;
if (foo) debugger; if (foo) debugger;

133
test/compress/directives.js Normal file
View File

@@ -0,0 +1,133 @@
simple_statement_is_not_a_directive: {
input: {
"use strict"
.split(" ")
.forEach(function(s) {
console.log(s);
});
console.log(!this); // is strict mode?
(function() {
"directive"
""
"use strict"
"hello world"
.split(" ")
.forEach(function(s) {
console.log(s);
});
console.log(!this); // is strict mode?
})();
}
expect: {
"use strict".split(" ").forEach(function(s) {
console.log(s);
});
console.log(!this);
(function() {
"directive";
"";
"use strict";
"hello world".split(" ").forEach(function(s) {
console.log(s);
});
console.log(!this);
})();
}
expect_stdout: [
"use",
"strict",
"false",
"hello",
"world",
"true",
]
}
drop_lone_use_strict: {
options = {
directives: true,
side_effects: true,
}
input: {
function f1() {
"use strict";
}
function f2() {
"use strict";
function f3() {
"use strict";
}
}
(function f4() {
"use strict";
})();
}
expect: {
function f1() {
}
function f2() {
"use strict";
function f3() {
}
}
}
}
issue_3166: {
options = {
directives: true,
}
input: {
"foo";
"use strict";
function f() {
"use strict";
"bar";
"use asm";
}
}
expect: {
"use strict";
function f() {
"use asm";
}
}
}
valid_after_invalid_1: {
input: {
console.log(typeof function() {
"use\x20strict";
"use strict";
return this;
}());
}
expect: {
console.log(typeof function() {
"use\x20strict";
"use strict";
return this;
}());
}
expect_stdout: "undefined"
}
valid_after_invalid_2: {
options = {
directives: true,
}
input: {
console.log(typeof function() {
"use\x20strict";
"use strict";
return this;
}());
}
expect: {
console.log(typeof function() {
"use strict";
return this;
}());
}
expect_stdout: "undefined"
}

View File

@@ -1,5 +1,5 @@
drop_console_1: { drop_console_1: {
options = {}; options = {}
input: { input: {
console.log('foo'); console.log('foo');
console.log.apply(console, arguments); console.log.apply(console, arguments);
@@ -11,7 +11,9 @@ drop_console_1: {
} }
drop_console_2: { drop_console_2: {
options = { drop_console: true }; options = {
drop_console: true,
}
input: { input: {
console.log('foo'); console.log('foo');
console.log.apply(console, arguments); console.log.apply(console, arguments);

View File

@@ -1,5 +1,8 @@
unused_funarg_1: { unused_funarg_1: {
options = { unused: true, keep_fargs: false }; options = {
keep_fargs: false,
unused: true,
}
input: { input: {
function f(a, b, c, d, e) { function f(a, b, c, d, e) {
return a + b; return a + b;
@@ -13,7 +16,10 @@ unused_funarg_1: {
} }
unused_funarg_2: { unused_funarg_2: {
options = { unused: true, keep_fargs: false }; options = {
keep_fargs: false,
unused: true,
}
input: { input: {
function f(a, b, c, d, e) { function f(a, b, c, d, e) {
return a + c; return a + c;
@@ -27,7 +33,9 @@ unused_funarg_2: {
} }
unused_nested_function: { unused_nested_function: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function f(x, y) { function f(x, y) {
function g() { function g() {
@@ -44,7 +52,9 @@ unused_nested_function: {
} }
unused_circular_references_1: { unused_circular_references_1: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function f(x, y) { function f(x, y) {
// circular reference // circular reference
@@ -65,7 +75,9 @@ unused_circular_references_1: {
} }
unused_circular_references_2: { unused_circular_references_2: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function f(x, y) { function f(x, y) {
var foo = 1, bar = baz, baz = foo + bar, qwe = moo(); var foo = 1, bar = baz, baz = foo + bar, qwe = moo();
@@ -81,7 +93,9 @@ unused_circular_references_2: {
} }
unused_circular_references_3: { unused_circular_references_3: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function f(x, y) { function f(x, y) {
var g = function() { return h() }; var g = function() { return h() };
@@ -97,7 +111,9 @@ unused_circular_references_3: {
} }
unused_keep_setter_arg: { unused_keep_setter_arg: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
var x = { var x = {
_foo: null, _foo: null,
@@ -121,12 +137,14 @@ unused_keep_setter_arg: {
} }
unused_var_in_catch: { unused_var_in_catch: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
} }
@@ -135,18 +153,20 @@ unused_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) {} } catch (ex) {}
} }
} }
} }
used_var_in_catch: { used_var_in_catch: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
return x; return x;
@@ -156,7 +176,7 @@ used_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
return x; return x;
@@ -165,7 +185,11 @@ used_var_in_catch: {
} }
keep_fnames: { keep_fnames: {
options = { unused: true, keep_fnames: true, unsafe: true }; options = {
keep_fnames: true,
unsafe: true,
unused: true,
}
input: { input: {
function foo() { function foo() {
return function bar(baz) {}; return function bar(baz) {};
@@ -367,7 +391,7 @@ drop_toplevel_vars_fargs: {
drop_toplevel_all: { drop_toplevel_all: {
options = { options = {
toplevel: true, toplevel: true,
unused: true unused: true,
} }
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
@@ -418,7 +442,11 @@ drop_toplevel_retain: {
drop_toplevel_retain_array: { drop_toplevel_retain_array: {
options = { options = {
top_retain: [ "f", "a", "o" ], top_retain: [
"f",
"a",
"o"
],
unused: true, unused: true,
} }
input: { input: {
@@ -476,8 +504,8 @@ drop_toplevel_retain_regex: {
drop_toplevel_all_retain: { drop_toplevel_all_retain: {
options = { options = {
toplevel: true,
top_retain: "f,a,o", top_retain: "f,a,o",
toplevel: true,
unused: true, unused: true,
} }
input: { input: {
@@ -506,8 +534,8 @@ drop_toplevel_all_retain: {
drop_toplevel_funcs_retain: { drop_toplevel_funcs_retain: {
options = { options = {
toplevel: "funcs",
top_retain: "f,a,o", top_retain: "f,a,o",
toplevel: "funcs",
unused: true, unused: true,
} }
input: { input: {
@@ -537,8 +565,8 @@ drop_toplevel_funcs_retain: {
drop_toplevel_vars_retain: { drop_toplevel_vars_retain: {
options = { options = {
toplevel: "vars",
top_retain: "f,a,o", top_retain: "f,a,o",
toplevel: "vars",
unused: true, unused: true,
} }
input: { input: {
@@ -671,18 +699,6 @@ iife: {
} }
} }
drop_value: {
options = {
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), bar();
}
}
issue_1539: { issue_1539: {
options = { options = {
collapse_vars: true, collapse_vars: true,
@@ -769,6 +785,7 @@ assign_chain: {
issue_1583: { issue_1583: {
options = { options = {
keep_fargs: true, keep_fargs: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
@@ -976,7 +993,7 @@ issue_1715_4: {
delete_assign_1: { delete_assign_1: {
options = { options = {
booleans: true, booleans: true,
side_effects: true, evaluate: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -990,21 +1007,28 @@ delete_assign_1: {
console.log(delete (a = 0 / 0)); console.log(delete (a = 0 / 0));
} }
expect: { expect: {
console.log((void 0, !0)); console.log(!0);
console.log((void 0, !0)); console.log(!0);
console.log((1 / 0, !0)); console.log(!0);
console.log((1 / 0, !0)); console.log(!0);
console.log((NaN, !0)); console.log(!0);
console.log((0 / 0, !0)); console.log(!0);
} }
expect_stdout: true expect_stdout: [
"true",
"true",
"true",
"true",
"true",
"true",
]
} }
delete_assign_2: { delete_assign_2: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -1018,14 +1042,21 @@ delete_assign_2: {
console.log(delete (a = 0 / 0)); console.log(delete (a = 0 / 0));
} }
expect: { expect: {
console.log((void 0, !0)); console.log(!0);
console.log((void 0, !0)); console.log(!0);
console.log((Infinity, !0)); console.log(!0);
console.log((1 / 0, !0)); console.log(!0);
console.log((NaN, !0)); console.log(!0);
console.log((0 / 0, !0)); console.log(!0);
} }
expect_stdout: true expect_stdout: [
"true",
"true",
"true",
"true",
"true",
"true",
]
} }
drop_var: { drop_var: {
@@ -1116,6 +1147,7 @@ var_catch_toplevel: {
options = { options = {
conditionals: true, conditionals: true,
negate_iife: true, negate_iife: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
@@ -1128,7 +1160,7 @@ var_catch_toplevel: {
try { try {
a++; a++;
x(); x();
} catch(a) { } catch (a) {
if (a) var a; if (a) var a;
var a = 10; var a = 10;
} }
@@ -1139,7 +1171,7 @@ var_catch_toplevel: {
!function() { !function() {
try { try {
x(); x();
} catch(a) { } catch (a) {
var a; var a;
} }
}(); }();
@@ -1159,10 +1191,10 @@ issue_2105_1: {
input: { input: {
!function(factory) { !function(factory) {
factory(); factory();
}( function() { }(function() {
return function(fn) { return function(fn) {
fn()().prop(); fn()().prop();
}( function() { }(function() {
function bar() { function bar() {
var quux = function() { var quux = function() {
console.log("PASS"); console.log("PASS");
@@ -1173,7 +1205,7 @@ issue_2105_1: {
return { prop: foo }; return { prop: foo };
} }
return bar; return bar;
} ); });
}); });
} }
expect: { expect: {
@@ -1203,10 +1235,10 @@ issue_2105_2: {
input: { input: {
!function(factory) { !function(factory) {
factory(); factory();
}( function() { }(function() {
return function(fn) { return function(fn) {
fn()().prop(); fn()().prop();
}( function() { }(function() {
function bar() { function bar() {
var quux = function() { var quux = function() {
console.log("PASS"); console.log("PASS");
@@ -1217,7 +1249,7 @@ issue_2105_2: {
return { prop: foo }; return { prop: foo };
} }
return bar; return bar;
} ); });
}); });
} }
expect: { expect: {
@@ -1226,6 +1258,44 @@ issue_2105_2: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2105_3: {
options = {
inline: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
!function(factory) {
factory();
}(function() {
return function(fn) {
fn()().prop();
}(function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
});
});
}
expect: {
!void void {
prop: function() {
console.log;
void console.log("PASS");
}
}.prop();
}
expect_stdout: "PASS"
}
issue_2226_1: { issue_2226_1: {
options = { options = {
side_effects: true, side_effects: true,
@@ -1377,9 +1447,9 @@ issue_2516_1: {
issue_2516_2: { issue_2516_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
passes: 2,
unused: true, unused: true,
} }
input: { input: {
@@ -1605,7 +1675,7 @@ double_assign_2: {
} }
expect: { expect: {
for (var i = 0; i < 2; i++) for (var i = 0; i < 2; i++)
void 0, a = {}, console.log(a); a = {}, console.log(a);
var a; var a;
} }
} }
@@ -1686,7 +1756,7 @@ issue_2768: {
} }
expect: { expect: {
var a = "FAIL"; var a = "FAIL";
var c = (d = a, 0, void (d && (a = "PASS"))); var c = (d = a, void (d && (a = "PASS")));
var d; var d;
console.log(a, typeof c); console.log(a, typeof c);
} }
@@ -1814,3 +1884,563 @@ issue_2995: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3146_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}
issue_3146_4: {
options = {
reduce_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}
issue_3192: {
options = {
unused: true,
}
input: {
(function(a) {
console.log(a = "foo", arguments[0]);
})("bar");
(function(a) {
"use strict";
console.log(a = "foo", arguments[0]);
})("bar");
}
expect: {
(function(a) {
console.log(a = "foo", arguments[0]);
})("bar");
(function(a) {
"use strict";
console.log("foo", arguments[0]);
})("bar");
}
expect_stdout: [
"foo foo",
"foo bar",
]
}
issue_3233: {
options = {
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a = function b() {
b.c = "PASS";
};
a();
console.log(a.c);
}
expect: {
var a = function b() {
b.c = "PASS";
};
a();
console.log(a.c);
}
expect_stdout: "PASS"
}
issue_3375: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
var a = c = [], c = --b + ("function" == typeof f && f());
var a = c && c[a];
console.log(a, b);
}
expect: {
var b = 1;
var a = [], c = --b + ("function" == typeof f && f());
a = c && c[a];
console.log(a, b);
}
expect_stdout: "0 0"
}
issue_3427_1: {
options = {
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a;
a = a || {};
})();
}
expect: {}
}
issue_3427_2: {
options = {
unused: true,
}
input: {
(function() {
var s = "PASS";
console.log(s = s || "FAIL");
})();
}
expect: {
(function() {
var s = "PASS";
console.log(s = s || "FAIL");
})();
}
expect_stdout: "PASS"
}
issue_3495: {
options = {
dead_code: true,
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
console.log(function f() {
f = 0;
var a = f.p;
}());
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
}
issue_3497: {
options = {
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a;
console.log(function(b) {
(b += a).p = 0;
}());
}
expect: {
var a;
console.log(function(b) {
(b += a).p = 0;
}());
}
expect_stdout: "undefined"
}
issue_3515_1: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var c = 0;
(function() {
this[c++] = 0;
var expr20 = !0;
for (var key20 in expr20);
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
this[c++] = 0;
for (var key20 in !0);
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3515_2: {
options = {
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL";
function f() {
typeof b === "number";
delete a;
}
var b = f(a = "PASS");
console.log(a);
}
expect: {
var a = "FAIL";
function f() {
delete a;
}
f(a = "PASS");
console.log(a);
}
expect_stdout: "PASS"
}
issue_3515_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var c = "FAIL";
(function() {
function f() {
c = "PASS";
}
var a = f();
var a = function g(b) {
b && (b.p = this);
}(a);
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function() {
function f() {
c = "PASS";
}
(function(b) {
b && (b.p = this);
})(f());
})();
console.log(c);
}
expect_stdout: "PASS"
}
function_assign: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function() {
var a = "PASS";
function g(b) {
return b;
}
g.p = a;
function h(c) {
return c;
}
h.p = a;
return h;
}().p);
}
expect: {
console.log(function() {
var a = "PASS";
function h(c) {
return c;
}
h.p = a;
return h;
}().p);
}
expect_stdout: "PASS"
}
issue_3598: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "FAIL";
try {
(function() {
var b = void 0;
a = "PASS";
c.p = 0;
var c = b[!1];
})();
} catch (e) {}
console.log(a);
}
expect: {
var a = "FAIL";
try {
(function() {
a = "PASS";
var c = (void (c.p = 0))[!1];
})();
} catch (e) {}
console.log(a);
}
expect_stdout: "PASS"
}
self_assign: {
options = {
passes: 2,
side_effects: true,
unused: true,
}
input: {
function d(a) {
a = a;
}
function e(a, b) {
a = b;
b = a;
}
function f(a, b, c) {
a = b;
b = c;
c = a;
}
function g(a, b, c) {
a = a * b + c;
}
}
expect: {
function d(a) {}
function e(a, b) {}
function f(a, b, c) {}
function g(a, b, c) {}
}
}
function_argument_reference: {
options = {
keep_fargs: false,
side_effects: true,
unused: true,
}
input: {
var a = 1, b = 42;
function f(a) {
b <<= a;
}
f();
console.log(a, b);
}
expect: {
var a = 1, b = 42;
function f(a) {
b <<= a;
}
f();
console.log(a, b);
}
expect_stdout: "1 42"
}
function_parameter_ie8: {
options = {
ie8: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
console.log("PASS");
}
f(a = 1 + a);
})();
}
expect: {
(function() {
(function f() {
console.log("PASS");
})();
})();
}
expect_stdout: "PASS"
}
issue_3664: {
options = {
pure_getters: "strict",
unused: true,
}
input: {
console.log(function() {
var a, b = (a = (a = [ b && console.log("FAIL") ]).p = 0, 0);
return "PASS";
}());
}
expect: {
console.log(function() {
var b = ([ b && console.log("FAIL") ].p = 0, 0);
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_3673: {
options = {
pure_getters: "strict",
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
(a = [ a ]).p = 42;
console.log("PASS");
}
expect: {
var a;
(a = [ a ]).p = 42;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_3746: {
options = {
keep_fargs: "strict",
side_effects: true,
unused: true,
}
input: {
try {
A;
} catch (e) {
var e;
}
(function f(a) {
e = a;
})();
console.log("PASS");
}
expect: {
try {
A;
} catch (e) {
var e;
}
(function(a) {
e = a;
})();
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -186,7 +186,9 @@ unary_prefix: {
} }
negative_zero: { negative_zero: {
options = { evaluate: true } options = {
evaluate: true,
}
input: { input: {
console.log( console.log(
-"", -"",
@@ -207,7 +209,9 @@ negative_zero: {
} }
positive_zero: { positive_zero: {
options = { evaluate: true } options = {
evaluate: true,
}
input: { input: {
console.log( console.log(
+"", +"",
@@ -229,26 +233,43 @@ positive_zero: {
unsafe_constant: { unsafe_constant: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(true.a, false.a);
true.a, console.log(true.valueOf(), false.valueOf());
false.a, try {
null.a, console.log(null.a);
undefined.a } catch (e) {
); console.log("PASS");
}
try {
console.log(undefined.a);
} catch (e) {
console.log("PASS");
}
} }
expect: { expect: {
console.log( console.log(void 0, void 0);
true.a, console.log(true, false);
false.a, try {
null.a, console.log(null.a);
(void 0).a } catch (e) {
); console.log("PASS");
} }
expect_stdout: true try {
console.log((void 0).a);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: [
"undefined undefined",
"true false",
"PASS",
"PASS",
]
} }
unsafe_object: { unsafe_object: {
@@ -274,7 +295,7 @@ unsafe_object: {
o + 1, o + 1,
2, 2,
o.b + 1, o.b + 1,
1..b + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -361,7 +382,7 @@ unsafe_object_repeated: {
o + 1, o + 1,
2, 2,
o.b + 1, o.b + 1,
1..b + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -421,8 +442,8 @@ prop_function: {
unsafe_integer_key: { unsafe_integer_key: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -440,8 +461,8 @@ unsafe_integer_key: {
2, 2,
2, 2,
({0:1})[1] + 1, ({0:1})[1] + 1,
1[1] + 1, NaN,
1["1"] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -449,8 +470,8 @@ unsafe_integer_key: {
unsafe_integer_key_complex: { unsafe_integer_key_complex: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -477,8 +498,8 @@ unsafe_integer_key_complex: {
unsafe_float_key: { unsafe_float_key: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -496,8 +517,8 @@ unsafe_float_key: {
2, 2,
2, 2,
({2.72:1})[3.14] + 1, ({2.72:1})[3.14] + 1,
1[3.14] + 1, NaN,
1["3.14"] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -505,8 +526,8 @@ unsafe_float_key: {
unsafe_float_key_complex: { unsafe_float_key_complex: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -533,8 +554,8 @@ unsafe_float_key_complex: {
unsafe_array: { unsafe_array: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -569,8 +590,8 @@ unsafe_array: {
unsafe_string: { unsafe_string: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -597,8 +618,8 @@ unsafe_string: {
unsafe_array_bad_index: { unsafe_array_bad_index: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -619,8 +640,8 @@ unsafe_array_bad_index: {
unsafe_string_bad_index: { unsafe_string_bad_index: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -631,12 +652,12 @@ unsafe_string_bad_index: {
} }
expect: { expect: {
console.log( console.log(
"1234".a + 1, NaN,
"1234"["a"] + 1, NaN,
"1234"[3.14] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: "NaN NaN NaN"
} }
prototype_function: { prototype_function: {
@@ -754,8 +775,8 @@ in_boolean_context: {
unsafe_charAt: { unsafe_charAt: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -782,8 +803,8 @@ unsafe_charAt: {
unsafe_charAt_bad_index: { unsafe_charAt_bad_index: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -804,8 +825,8 @@ unsafe_charAt_bad_index: {
unsafe_charAt_noop: { unsafe_charAt_noop: {
options = { options = {
evaluate : true, evaluate: true,
unsafe : true unsafe: true,
} }
input: { input: {
console.log( console.log(
@@ -816,8 +837,8 @@ unsafe_charAt_noop: {
} }
expect: { expect: {
console.log( console.log(
s.charAt(0), s[0],
"string".charAt(x), "string"[0 | x],
(typeof x)[0] (typeof x)[0]
); );
} }
@@ -1120,14 +1141,14 @@ issue_2207_1: {
console.log(Math.max(3, 6, 2, 7, 3, 4)); console.log(Math.max(3, 6, 2, 7, 3, 4));
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(Math.cos(1.2345) - Math.sin(4.321)); console.log(Math.cos(1.2345) - Math.sin(4.321));
console.log(Math.pow(Math.PI, Math.E - Math.LN10)); console.log(Math.pow(Math.PI, Math.E - Math.LN10).toFixed(15));
} }
expect: { expect: {
console.log("A"); console.log("A");
console.log(7); console.log(7);
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(1.2543732512566947); console.log(1.2543732512566947);
console.log(1.6093984514472044); console.log("1.609398451447204");
} }
expect_stdout: true expect_stdout: true
} }
@@ -1195,7 +1216,7 @@ issue_2231_1: {
} }
expect_stdout: true expect_stdout: true
expect_warnings: [ expect_warnings: [
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1191,20]", "WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1,20]",
] ]
} }
@@ -1212,7 +1233,7 @@ issue_2231_2: {
} }
expect_stdout: true expect_stdout: true
expect_warnings: [ expect_warnings: [
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1208,20]", "WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1,20]",
] ]
} }
@@ -1241,12 +1262,12 @@ self_comparison_1: {
} }
input: { input: {
var o = { n: NaN }; var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n); console.log(typeof o.n, o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n);
} }
expect: { expect: {
console.log(false, false, true, true, "number"); console.log("number", false, false, true, true);
} }
expect_stdout: "false false true true 'number'" expect_stdout: "number false false true true"
} }
self_comparison_2: { self_comparison_2: {
@@ -1261,12 +1282,12 @@ self_comparison_2: {
} }
input: { input: {
var o = { n: NaN }; var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n); console.log(typeof o.n, o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n);
} }
expect: { expect: {
console.log(false, false, true, true, "number"); console.log("number", false, false, true, true);
} }
expect_stdout: "false false true true 'number'" expect_stdout: "number false false true true"
} }
issue_2535_1: { issue_2535_1: {
@@ -1350,14 +1371,14 @@ issue_2535_3: {
} }
expect_stdout: true expect_stdout: true
expect_warnings: [ expect_warnings: [
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1336,20]", "WARN: Dropping side-effect-free && [test/compress/evaluate.js:1,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1337,20]", "WARN: Dropping side-effect-free && [test/compress/evaluate.js:2,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1338,20]", "WARN: Dropping side-effect-free && [test/compress/evaluate.js:3,20]",
"WARN: Condition left of && always false [test/compress/evaluate.js:1338,20]", "WARN: Condition left of && always false [test/compress/evaluate.js:3,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1339,20]", "WARN: Dropping side-effect-free || [test/compress/evaluate.js:4,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1340,20]", "WARN: Dropping side-effect-free || [test/compress/evaluate.js:5,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1341,20]", "WARN: Dropping side-effect-free || [test/compress/evaluate.js:6,20]",
"WARN: Condition left of || always true [test/compress/evaluate.js:1341,20]", "WARN: Condition left of || always true [test/compress/evaluate.js:6,20]",
] ]
} }
@@ -1536,7 +1557,7 @@ issue_2926_2: {
expect_stdout: "function" expect_stdout: "function"
} }
issue_2968: { issue_2968_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
@@ -1567,6 +1588,39 @@ issue_2968: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2968_2: {
options = {
assignments: true,
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var c = "FAIL";
(function() {
(function(a, b) {
a <<= 0;
a && (a[(c = "PASS", 0 >>> (b += 1))] = 0);
})(42, -42);
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function() {
a = 42,
((a <<= 0) && (a[(c = "PASS", 0)] = 0));
var a;
})();
console.log(c);
}
expect_stdout: "PASS"
}
truthy_conditionals: { truthy_conditionals: {
options = { options = {
conditionals: true, conditionals: true,
@@ -1606,3 +1660,533 @@ truthy_loops: {
} }
} }
} }
if_increment: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
if (console)
return ++a;
}(0));
}
expect: {
console.log(function(a) {
if (console)
return 1;
}());
}
expect_stdout: "1"
}
try_increment: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
try {
return ++a;
} catch (e) {}
}(0));
}
expect: {
console.log(function(a) {
try {
return 1;
} catch (e) {}
}());
}
expect_stdout: "1"
}
unsafe_escaped: {
options = {
evaluate: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
(function(a) {
console.log(function(index) {
return a[index];
}(function(term) {
return a.indexOf(term);
}("PASS")));
})([ "PASS" ]);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
unsafe_string_replace: {
options = {
evaluate: true,
unsafe: true,
}
input: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3387_1: {
options = {
evaluate: true,
}
input: {
console.log(1 + (2 + "3"[4]));
}
expect: {
console.log(1 + (2 + "3"[4]));
}
expect_stdout: "NaN"
}
issue_3387_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(1 + (2 + "3"[4]));
}
expect: {
console.log(NaN);
}
expect_stdout: "NaN"
}
simple_function_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function sum(a, b) {
return a + b;
}
console.log(sum(1, 2) * sum(3, 4));
}
expect: {
console.log(21);
}
expect_stdout: "21"
}
simple_function_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var sum = function(a, b) {
return a + b;
}
console.log(sum(1, 2) * sum(3, 4));
}
expect: {
console.log(21);
}
expect_stdout: "21"
}
recursive_function_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function factorial(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect: {
console.log(function factorial(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}(5));
}
expect_stdout: "120"
}
recursive_function_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var factorial = function(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect: {
var factorial = function(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect_stdout: "120"
}
issue_3558: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f(a) {
return 1 + --a;
}
console.log(f(true), f(false));
}
expect: {
function f(a) {
return 1 + --a;
}
console.log(1, 0);
}
expect_stdout: "1 0"
}
issue_3568: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var a = 0;
function f(b) {
return b && b.p;
}
console.log(f(++a + f()));
}
expect: {
var a = 0;
function f(b) {
return b && b.p;
}
console.log(NaN);
}
expect_stdout: "NaN"
}
conditional_function: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f(a) {
return a && "undefined" != typeof A ? A : 42;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
return a && "undefined" != typeof A ? A : 42;
}
console.log(42, f(1));
}
expect_stdout: "42 42"
}
best_of_evaluate: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function d(x, y) {
return x / y;
}
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
}
expect: {
function d(x, y) {
return x / y;
}
console.log(0, 1 / 64, 4 / 7, 1);
console.log(0, .015625, d(4, 7), 1);
}
expect_stdout: [
"0 0.015625 0.5714285714285714 1",
"0 0.015625 0.5714285714285714 1",
]
}
eager_evaluate: {
options = {
evaluate: "eager",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function d(x, y) {
return x / y;
}
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
}
expect: {
console.log(0, .015625, .5714285714285714, 1);
console.log(0, .015625, .5714285714285714, 1);
}
expect_stdout: [
"0 0.015625 0.5714285714285714 1",
"0 0.015625 0.5714285714285714 1",
]
}
threshold_evaluate_default: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b(b(b("ABCDEFGHIJK"))));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_30: {
options = {
evaluate: 30,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b(b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK")));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_100: {
options = {
evaluate: 100,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_999: {
options = {
evaluate: 999,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
console.log("111", 6, "ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK");
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
collapse_vars_regexp: {
options = {
booleans: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: false,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_regexp: true,
unused: true,
}
input: {
function f1() {
var k = 9;
var rx = /[A-Z]+/;
return [rx, k];
}
function f2() {
var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
function f3() {
var rx = /ab*/g;
return function() {
return rx;
};
}
(function() {
var result;
var s = "acdabcdeabbb";
var rx = /ab*/g;
while (result = rx.exec(s))
console.log(result[0]);
})();
(function() {
var result;
var s = "acdabcdeabbb";
var rx = f2();
while (result = rx(s))
console.log(result[0]);
})();
(function() {
var result;
var s = "acdabcdeabbb";
var rx = f3();
while (result = rx().exec(s))
console.log(result[0]);
})();
}
expect: {
function f1() {
return [/[A-Z]+/, 9];
}
function f2() {
var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
function f3() {
var rx = /ab*/g;
return function() {
return rx;
};
}
(function() {
var result, rx = /ab*/g;
while (result = rx.exec("acdabcdeabbb"))
console.log(result[0]);
})();
(function() {
var result, rx = f2();
while (result = rx("acdabcdeabbb"))
console.log(result[0]);
})();
(function() {
var result, rx = f3();
while (result = rx().exec("acdabcdeabbb"))
console.log(result[0]);
})();
}
expect_stdout: [
"a",
"ab",
"abbb",
"a",
"ab",
"abbb",
"a",
"ab",
"abbb",
]
}
issue_3738: {
options = {
evaluate: true,
}
input: {
console.log(1 / (0 + ([] - 1) % 1));
}
expect: {
console.log(1 / (0 + ([] - 1) % 1));
}
expect_stdout: "Infinity"
}
issue_3755: {
options = {
booleans: true,
evaluate: true,
unsafe: true,
unsafe_math: true,
}
input: {
console.log((/4/.exec(1 + (!0 - 5 / "23")) || 0).p);
}
expect: {
console.log((/4/.exec(!0 - 5 / "23" + 1), 0).p);
}
expect_stdout: "undefined"
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ must_replace: {
options = { options = {
global_defs: { global_defs: {
D: "foo bar", D: "foo bar",
} },
} }
input: { input: {
console.log(D); console.log(D);
@@ -141,9 +141,8 @@ mixed: {
console.log(CONFIG); console.log(CONFIG);
} }
expect_warnings: [ expect_warnings: [
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]', "WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]",
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]', "WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]",
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]',
] ]
} }
@@ -197,3 +196,23 @@ issue_2167: {
doWork(); doWork();
} }
} }
issue_3217: {
options = {
collapse_vars: true,
global_defs: {
"@o": "{fn:function(){var a=42;console.log(a)}}",
},
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
o.fn();
}
expect: {
console.log(42);
}
}

View File

@@ -1,8 +1,8 @@
issue_2377_1: { issue_2377_1: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
hoist_props: true, hoist_props: true,
inline: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
@@ -33,8 +33,8 @@ issue_2377_1: {
issue_2377_2: { issue_2377_2: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
hoist_props: true, hoist_props: true,
inline: true,
passes: 2, passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
@@ -64,8 +64,8 @@ issue_2377_2: {
issue_2377_3: { issue_2377_3: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
hoist_props: true, hoist_props: true,
inline: true,
passes: 4, passes: 4,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
@@ -416,7 +416,10 @@ issue_2473_1: {
options = { options = {
hoist_props: false, hoist_props: false,
reduce_vars: true, reduce_vars: true,
top_retain: [ "x", "y" ], top_retain: [
"x",
"y"
],
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -435,7 +438,10 @@ issue_2473_2: {
options = { options = {
hoist_props: true, hoist_props: true,
reduce_vars: true, reduce_vars: true,
top_retain: [ "x", "y" ], top_retain: [
"x",
"y"
],
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -658,7 +664,7 @@ issue_2519: {
} }
expect: { expect: {
function testFunc() { function testFunc() {
return 1 * ((6 + 5) / 2); return +((6 + 5) / 2);
} }
console.log(testFunc()); console.log(testFunc());
} }
@@ -742,3 +748,169 @@ issue_3046: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_3071_1: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
join_vars: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
var obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
join_vars: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2_toplevel: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
join_vars: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_3: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect_stdout: "2"
}
issue_3411: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var c = 1;
!function f() {
var o = {
p: --c && f()
};
+o || console.log("PASS");
}();
}
expect: {
var c = 1;
!function f() {
var o_p = --c && f();
+{} || console.log("PASS");
}();
}
expect_stdout: "PASS"
}
issue_3440: {
options = {
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
function f() {
console.log(o.p);
}
var o = {
p: "PASS",
};
return f;
})()();
}
expect: {
(function() {
var o_p = "PASS";
return function() {
console.log(o_p);
};
})()();
}
expect_stdout: "PASS"
}

View File

@@ -1,55 +1,107 @@
html_comment_in_expression: { html_comment_in_expression: {
input: { input: {
function f(a, b, x, y) { return a < !--b && x-- > y; } (function(a, b) {
console.log(a < !--b && a-- > b, a, b);
})(1, 2);
} }
expect_exact: "function f(a,b,x,y){return a< !--b&&x-- >y}"; expect_exact: "(function(a,b){console.log(a<! --b&&a-- >b,a,b)})(1,2);"
expect_stdout: "false 1 1"
} }
html_comment_in_less_than: { html_comment_in_less_than: {
input: { input: {
function f(a, b) { return a < !--b; } (function(a, b, c) {
console.log(
a < !--b,
a < !--b + c,
a + b < !--c,
a, b, c
);
})(1, 2, 3);
} }
expect_exact: "function f(a,b){return a< !--b}"; expect_exact: "(function(a,b,c){console.log(a<! --b,a<! --b+c,a+b<! --c,a,b,c)})(1,2,3);"
expect_stdout: "false true false 1 0 2"
} }
html_comment_in_left_shift: { html_comment_in_left_shift: {
input: { input: {
function f(a, b) { return a << !--b; } (function(a, b, c) {
console.log(
a << !--b,
a << !--b + c,
a + b << !--c,
a, b, c
);
})(1, 2, 3);
} }
expect_exact: "function f(a,b){return a<< !--b}"; expect_exact: "(function(a,b,c){console.log(a<<! --b,a<<! --b+c,a+b<<! --c,a,b,c)})(1,2,3);"
} expect_stdout: "1 16 1 1 0 2"
html_comment_in_right_shift: {
input: {
function f(a, b) { return a-- >> b; }
}
expect_exact: "function f(a,b){return a-- >>b}";
}
html_comment_in_zero_fill_right_shift: {
input: {
function f(a, b) { return a-- >>> b; }
}
expect_exact: "function f(a,b){return a-- >>>b}";
} }
html_comment_in_greater_than: { html_comment_in_greater_than: {
input: { input: {
function f(a, b) { return a-- > b; } (function(a, b, c) {
console.log(
a-- > b,
a-- > b + c,
a + b-- > c,
a, b, c
);
})(1, 2, 3);
} }
expect_exact: "function f(a,b){return a-- >b}"; expect_exact: "(function(a,b,c){console.log(a-- >b,a-- >b+c,a+b-- >c,a,b,c)})(1,2,3);"
expect_stdout: "false false false -1 1 3"
} }
html_comment_in_greater_than_or_equal: { html_comment_in_greater_than_or_equal: {
input: { input: {
function f(a, b) { return a-- >= b; } (function(a, b, c) {
console.log(
a-- >= b,
a-- >= b + c,
a + b-- >= c,
a, b, c
);
})(1, 2, 3);
} }
expect_exact: "function f(a,b){return a-- >=b}"; expect_exact: "(function(a,b,c){console.log(a-- >=b,a-- >=b+c,a+b-- >=c,a,b,c)})(1,2,3);"
expect_stdout: "false false false -1 1 3"
}
html_comment_in_right_shift: {
input: {
(function(a, b, c) {
console.log(
a-- >> b,
a-- >> b + c,
a + b-- >> c,
a, b, c
);
})(1, 2, 3);
}
expect_exact: "(function(a,b,c){console.log(a-- >>b,a-- >>b+c,a+b-- >>c,a,b,c)})(1,2,3);"
expect_stdout: "0 0 0 -1 1 3"
}
html_comment_in_zero_fill_right_shift: {
input: {
(function(a, b, c) {
console.log(
a-- >>> b,
a-- >>> b + c,
a + b-- >>> c,
a, b, c
);
})(1, 2, 3);
}
expect_exact: "(function(a,b,c){console.log(a-- >>>b,a-- >>>b+c,a+b-- >>>c,a,b,c)})(1,2,3);"
expect_stdout: "0 0 0 -1 1 3"
} }
html_comment_in_string_literal: { html_comment_in_string_literal: {
input: { input: {
function f() { return "<!--HTML-->comment in<!--string literal-->"; } console.log("<!--HTML-->comment in<!--string literal-->".length);
} }
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}'; expect_exact: 'console.log("\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e".length);'
expect_stdout: "42"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
if_return_1: { if_return_1: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x) { function f(x) {
@@ -24,15 +24,15 @@ if_return_1: {
if_return_2: { if_return_2: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x, y) { function f(x, y) {
@@ -49,15 +49,15 @@ if_return_2: {
if_return_3: { if_return_3: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x) { function f(x) {
@@ -75,15 +75,15 @@ if_return_3: {
if_return_4: { if_return_4: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x, y) { function f(x, y) {
@@ -100,15 +100,15 @@ if_return_4: {
if_return_5: { if_return_5: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f() { function f() {
@@ -126,15 +126,15 @@ if_return_5: {
if_return_6: { if_return_6: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x) { function f(x) {
@@ -150,15 +150,15 @@ if_return_6: {
if_return_7: { if_return_7: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function f(x) { function f(x) {
@@ -176,10 +176,10 @@ if_return_7: {
if_return_8: { if_return_8: {
options = { options = {
conditionals: true,
if_return: true, if_return: true,
sequences: true, sequences: true,
conditionals: true, side_effects: true,
side_effects : true,
} }
input: { input: {
function f(e) { function f(e) {
@@ -220,15 +220,15 @@ if_return_8: {
issue_1089: { issue_1089: {
options = { options = {
if_return : true, booleans: true,
sequences : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
evaluate : true, evaluate: true,
booleans : true, if_return: true,
unused : true, sequences: true,
side_effects : true, side_effects: true,
dead_code : true, unused: true,
} }
input: { input: {
function x() { function x() {
@@ -251,9 +251,9 @@ issue_1089: {
issue_1437: { issue_1437: {
options = { options = {
if_return : true, conditionals: false,
sequences : true, if_return: true,
conditionals : false sequences: true,
} }
input: { input: {
function x() { function x() {
@@ -281,9 +281,9 @@ issue_1437: {
issue_1437_conditionals: { issue_1437_conditionals: {
options = { options = {
conditionals : true, conditionals: true,
if_return : true, if_return: true,
sequences : true sequences: true,
} }
input: { input: {
function x() { function x() {
@@ -396,3 +396,180 @@ if_if_return_return: {
} }
} }
} }
if_body_return_1: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}
if_body_return_2: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (0 + a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (0 + a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}
if_body_return_3: {
options = {
if_return: true,
}
input: {
var c = "PASS";
function f(a, b) {
if (1 == a) {
if (b) throw new Error(c);
return 42;
}
return true;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect: {
var c = "PASS";
function f(a, b) {
if (1 != a) return true;
if (b) throw new Error(c);
return 42;
}
console.log(f(0, 0));
console.log(f(0, 1));
console.log(f(1, 0));
try {
f(1, 1);
console.log("FAIL");
} catch (e) {
console.log(e.message);
}
}
expect_stdout: [
"true",
"true",
"42",
"PASS",
]
}
issue_3600: {
options = {
if_return: true,
inline: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
(function() {
if ([ ][c++]); else return;
return void function() {
var b = --b, a = c = 42;
return c;
}();
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
if ([][c++]) b = --b, c = 42;
var b;
})();
console.log(c);
}
expect_stdout: "1"
}

View File

@@ -1,8 +1,17 @@
non_hoisted_function_after_return: { non_hoisted_function_after_return: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, comparisons: true,
if_return: true, join_vars: true, side_effects: true conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -21,25 +30,35 @@ non_hoisted_function_after_return: {
} }
expect: { expect: {
function foo(x) { function foo(x) {
return x ? bar() : baz(); return (x ? bar : baz)();
function bar() { return 7 } function bar() { return 7 }
function baz() { return 8 } function baz() { return 8 }
} }
} }
expect_warnings: [ expect_warnings: [
'WARN: Dropping unreachable code [test/compress/issue-1034.js:11,16]', "WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:14,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:17,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:18,21]" "WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
] ]
} }
non_hoisted_function_after_return_2a: { non_hoisted_function_after_return_2a: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, collapse_vars: false,
if_return: true, join_vars: true, side_effects: true, comparisons: true,
collapse_vars: false, passes: 2, warnings: "verbose" conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
passes: 2,
side_effects: true,
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -65,28 +84,37 @@ non_hoisted_function_after_return_2a: {
} }
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:48,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:48,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
"WARN: pass 0: last_count: Infinity, count: 37", "INFO: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
"WARN: pass 1: last_count: 37, count: 18", "INFO: pass 1: last_count: 37, count: 18",
] ]
} }
non_hoisted_function_after_return_2b: { non_hoisted_function_after_return_2b: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, collapse_vars: false,
if_return: true, join_vars: true, side_effects: true, comparisons: true,
collapse_vars: false conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -110,20 +138,28 @@ non_hoisted_function_after_return_2b: {
} }
} }
expect_warnings: [ expect_warnings: [
// duplicate warnings no longer emitted "WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:103,12]",
] ]
} }
non_hoisted_function_after_return_strict: { non_hoisted_function_after_return_strict: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, comparisons: true,
if_return: true, join_vars: true, side_effects: true conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
} }
input: { input: {
"use strict"; "use strict";
@@ -145,7 +181,7 @@ non_hoisted_function_after_return_strict: {
expect: { expect: {
"use strict"; "use strict";
function foo(x) { function foo(x) {
return x ? bar() : baz(); return (x ? bar : baz)();
function bar() { return 7 } function bar() { return 7 }
function baz() { return 8 } function baz() { return 8 }
} }
@@ -153,19 +189,29 @@ non_hoisted_function_after_return_strict: {
} }
expect_stdout: "8 7" expect_stdout: "8 7"
expect_warnings: [ expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:11,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:140,21]", "WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:12,21]",
] ]
} }
non_hoisted_function_after_return_2a_strict: { non_hoisted_function_after_return_2a_strict: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, collapse_vars: false,
if_return: true, join_vars: true, side_effects: true, comparisons: true,
collapse_vars: false, passes: 2, warnings: "verbose" conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
passes: 2,
side_effects: true,
unused: true,
} }
input: { input: {
"use strict"; "use strict";
@@ -196,28 +242,37 @@ non_hoisted_function_after_return_2a_strict: {
} }
expect_stdout: "5 6" expect_stdout: "5 6"
expect_warnings: [ expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
"WARN: pass 0: last_count: Infinity, count: 48", "INFO: pass 0: last_count: Infinity, count: 48",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:178,20]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:180,16]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
"WARN: pass 1: last_count: 48, count: 29", "INFO: pass 1: last_count: 48, count: 29",
] ]
} }
non_hoisted_function_after_return_2b_strict: { non_hoisted_function_after_return_2b_strict: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, booleans: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, collapse_vars: false,
if_return: true, join_vars: true, side_effects: true, comparisons: true,
collapse_vars: false conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: false,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
side_effects: true,
unused: true,
} }
input: { input: {
"use strict"; "use strict";
@@ -246,11 +301,10 @@ non_hoisted_function_after_return_2b_strict: {
} }
expect_stdout: "5 6" expect_stdout: "5 6"
expect_warnings: [ expect_warnings: [
// duplicate warnings no longer emitted "WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:231,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:235,12]",
] ]
} }

View File

@@ -3,7 +3,7 @@ const_pragma: {
evaluate: true, evaluate: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; }
input: { input: {
/** @const */ var goog = goog || {}; /** @const */ var goog = goog || {};
@@ -19,7 +19,7 @@ not_const: {
evaluate: true, evaluate: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; }
input: { input: {
var goog = goog || {}; var goog = goog || {};

View File

@@ -1,6 +1,6 @@
with_in_global_scope: { with_in_global_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
var o = 42; var o = 42;
@@ -18,7 +18,7 @@ with_in_global_scope: {
} }
with_in_function_scope: { with_in_function_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
function foo() { function foo() {
@@ -40,7 +40,7 @@ with_in_function_scope: {
} }
compress_with_with_in_other_scope: { compress_with_with_in_other_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
function foo() { function foo() {
@@ -69,7 +69,7 @@ compress_with_with_in_other_scope: {
} }
with_using_existing_variable_outside_scope: { with_using_existing_variable_outside_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
function f() { function f() {
@@ -99,7 +99,7 @@ with_using_existing_variable_outside_scope: {
} }
check_drop_unused_in_peer_function: { check_drop_unused_in_peer_function: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
function outer() { function outer() {
@@ -148,7 +148,7 @@ check_drop_unused_in_peer_function: {
Infinity_not_in_with_scope: { Infinity_not_in_with_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
var o = { Infinity: 'oInfinity' }; var o = { Infinity: 'oInfinity' };
@@ -164,7 +164,7 @@ Infinity_not_in_with_scope: {
Infinity_in_with_scope: { Infinity_in_with_scope: {
options = { options = {
unused: true unused: true,
} }
input: { input: {
var o = { Infinity: 'oInfinity' }; var o = { Infinity: 'oInfinity' };
@@ -180,19 +180,19 @@ Infinity_in_with_scope: {
assorted_Infinity_NaN_undefined_in_with_scope: { assorted_Infinity_NaN_undefined_in_with_scope: {
options = { options = {
unused: true,
evaluate: true,
dead_code: true,
conditionals: true,
comparisons: true,
booleans: true, booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true, hoist_funs: true,
keep_fargs: true,
if_return: true, if_return: true,
join_vars: true, join_vars: true,
side_effects: true, keep_fargs: true,
sequences: false,
keep_infinity: false, keep_infinity: false,
sequences: false,
side_effects: true,
unused: true,
} }
input: { input: {
var f = console.log; var f = console.log;
@@ -242,19 +242,19 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: { assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
options = { options = {
unused: true,
evaluate: true,
dead_code: true,
conditionals: true,
comparisons: true,
booleans: true, booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true, hoist_funs: true,
keep_fargs: true,
if_return: true, if_return: true,
join_vars: true, join_vars: true,
side_effects: true, keep_fargs: true,
sequences: false,
keep_infinity: true, keep_infinity: true,
sequences: false,
side_effects: true,
unused: true,
} }
input: { input: {
var f = console.log; var f = console.log;

View File

@@ -1,11 +1,15 @@
keep_name_of_getter: { keep_name_of_getter: {
options = { unused: true }; options = {
unused: true,
}
input: { a = { get foo () {} } } input: { a = { get foo () {} } }
expect: { a = { get foo () {} } } expect: { a = { get foo () {} } }
} }
keep_name_of_setter: { keep_name_of_setter: {
options = { unused: true }; options = {
unused: true,
}
input: { a = { set foo () {} } } input: { a = { set foo () {} } }
expect: { a = { set foo () {} } } expect: { a = { set foo () {} } }
} }

View File

@@ -1,7 +1,7 @@
mangle_keep_fnames_false: { mangle_keep_fnames_false: {
options = { options = {
keep_fnames : true, keep_fargs: true,
keep_fargs : true, keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames : false, keep_fnames : false,
@@ -26,8 +26,8 @@ mangle_keep_fnames_false: {
mangle_keep_fnames_true: { mangle_keep_fnames_true: {
options = { options = {
keep_fnames : true, keep_fargs: true,
keep_fargs : true, keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames : true, keep_fnames : true,

View File

@@ -1,14 +1,14 @@
pure_function_calls: { pure_function_calls: {
options = { options = {
evaluate : true, booleans: true,
conditionals : true, comparisons: true,
comparisons : true, conditionals: true,
side_effects : true, evaluate: true,
booleans : true, if_return: true,
unused : true, join_vars: true,
if_return : true, negate_iife: true,
join_vars : true, side_effects: true,
negate_iife : true, unused: true,
} }
input: { input: {
// pure top-level IIFE will be dropped // pure top-level IIFE will be dropped
@@ -48,28 +48,28 @@ pure_function_calls: {
a.b(), f.g(); a.b(), f.g();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:16,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:29,37]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:29,16]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:27,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:37,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:25,31]",
] ]
} }
pure_function_calls_toplevel: { pure_function_calls_toplevel: {
options = { options = {
evaluate : true, booleans: true,
conditionals : true, comparisons: true,
comparisons : true, conditionals: true,
side_effects : true, evaluate: true,
booleans : true, if_return: true,
unused : true, join_vars: true,
if_return : true, negate_iife: true,
join_vars : true, side_effects: true,
negate_iife : true, toplevel: true,
toplevel : true, unused: true,
} }
input: { input: {
// pure top-level IIFE will be dropped // pure top-level IIFE will be dropped
@@ -110,17 +110,17 @@ pure_function_calls_toplevel: {
a.b(), f.g(); a.b(), f.g();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:77,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:77,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:90,37]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:90,16]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:88,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:105,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:31,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:106,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:32,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:82,33]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:82,12]", "WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:8,12]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:98,45]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,45]",
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:98,12]", "WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:24,12]",
] ]
} }
@@ -155,29 +155,29 @@ should_warn: {
baz(); baz();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,61]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,61]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:135,23]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:1,23]",
"WARN: Boolean || always true [test/compress/issue-1261.js:136,23]", "WARN: Boolean || always true [test/compress/issue-1261.js:2,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:2,23]",
"WARN: Condition always true [test/compress/issue-1261.js:136,23]", "WARN: Condition always true [test/compress/issue-1261.js:2,23]",
"WARN: Condition left of || always true [test/compress/issue-1261.js:137,8]", "WARN: Condition left of || always true [test/compress/issue-1261.js:3,8]",
"WARN: Condition always true [test/compress/issue-1261.js:137,8]", "WARN: Condition always true [test/compress/issue-1261.js:3,8]",
"WARN: Boolean && always false [test/compress/issue-1261.js:138,23]", "WARN: Boolean && always false [test/compress/issue-1261.js:4,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:4,23]",
"WARN: Condition always false [test/compress/issue-1261.js:138,23]", "WARN: Condition always false [test/compress/issue-1261.js:4,23]",
"WARN: Condition left of && always false [test/compress/issue-1261.js:139,8]", "WARN: Condition left of && always false [test/compress/issue-1261.js:5,8]",
"WARN: Condition always false [test/compress/issue-1261.js:139,8]", "WARN: Condition always false [test/compress/issue-1261.js:5,8]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:140,23]", "WARN: + in boolean context always true [test/compress/issue-1261.js:6,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:6,23]",
"WARN: Condition always true [test/compress/issue-1261.js:140,23]", "WARN: Condition always true [test/compress/issue-1261.js:6,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:141,8]", "WARN: + in boolean context always true [test/compress/issue-1261.js:7,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:141,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:7,31]",
"WARN: Condition always true [test/compress/issue-1261.js:141,8]", "WARN: Condition always true [test/compress/issue-1261.js:7,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,23]",
"WARN: Condition always true [test/compress/issue-1261.js:143,8]", "WARN: Condition always true [test/compress/issue-1261.js:9,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:9,24]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:10,31]",
"WARN: Condition always false [test/compress/issue-1261.js:144,8]", "WARN: Condition always false [test/compress/issue-1261.js:10,8]",
] ]
} }

View File

@@ -1,16 +1,16 @@
string_plus_optimization: { string_plus_optimization: {
options = { options = {
side_effects : true, booleans: true,
evaluate : true, comparisons: true,
conditionals : true, conditionals: true,
comparisons : true, dead_code: true,
dead_code : true, evaluate: true,
booleans : true, hoist_funs: true,
unused : true, if_return: true,
if_return : true, join_vars: true,
join_vars : true, side_effects: true,
hoist_funs : true, unused: true,
}; }
input: { input: {
function foo(anything) { function foo(anything) {
function throwing_function() { function throwing_function() {

View File

@@ -15,7 +15,7 @@
tranformation_sort_order_equal: { tranformation_sort_order_equal: {
options = { options = {
comparisons: true, comparisons: true,
}; }
input: { (a = parseInt('100')) == a } input: { (a = parseInt('100')) == a }
expect: { (a = parseInt('100')) == a } expect: { (a = parseInt('100')) == a }
@@ -24,7 +24,7 @@ tranformation_sort_order_equal: {
tranformation_sort_order_unequal: { tranformation_sort_order_unequal: {
options = { options = {
comparisons: true, comparisons: true,
}; }
input: { (a = parseInt('100')) != a } input: { (a = parseInt('100')) != a }
expect: { (a = parseInt('100')) != a } expect: { (a = parseInt('100')) != a }
@@ -33,7 +33,7 @@ tranformation_sort_order_unequal: {
tranformation_sort_order_lesser_or_equal: { tranformation_sort_order_lesser_or_equal: {
options = { options = {
comparisons: true, comparisons: true,
}; }
input: { (a = parseInt('100')) <= a } input: { (a = parseInt('100')) <= a }
expect: { (a = parseInt('100')) <= a } expect: { (a = parseInt('100')) <= a }
@@ -41,7 +41,7 @@ tranformation_sort_order_lesser_or_equal: {
tranformation_sort_order_greater_or_equal: { tranformation_sort_order_greater_or_equal: {
options = { options = {
comparisons: true, comparisons: true,
}; }
input: { (a = parseInt('100')) >= a } input: { (a = parseInt('100')) >= a }
expect: { (a = parseInt('100')) >= a } expect: { (a = parseInt('100')) >= a }

View File

@@ -1,6 +1,6 @@
level_zero: { level_zero: {
options = { options = {
keep_fnames: true keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames: true keep_fnames: true
@@ -29,7 +29,7 @@ level_zero: {
level_one: { level_one: {
options = { options = {
keep_fnames: true keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames: true keep_fnames: true
@@ -58,7 +58,7 @@ level_one: {
level_two: { level_two: {
options = { options = {
keep_fnames: true keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames: true keep_fnames: true
@@ -97,7 +97,7 @@ level_two: {
level_three: { level_three: {
options = { options = {
keep_fnames: true keep_fnames: true,
} }
mangle = { mangle = {
keep_fnames: true keep_fnames: true

View File

@@ -22,17 +22,17 @@ else_with_empty_statement: {
conditional_false_stray_else_in_loop: { conditional_false_stray_else_in_loop: {
options = { options = {
evaluate : true, booleans: true,
comparisons : true, comparisons: true,
booleans : true, conditionals: false,
unused : true, dead_code: true,
loops : true, evaluate: true,
side_effects : true, hoist_vars: true,
dead_code : true, if_return: true,
hoist_vars : true, join_vars: true,
join_vars : true, loops: true,
if_return : true, side_effects: true,
conditionals : false, unused: true,
} }
input: { input: {
for (var i = 1; i <= 4; ++i) { for (var i = 1; i <= 4; ++i) {

View File

@@ -52,3 +52,30 @@ chained_evaluation_2: {
})(); })();
} }
} }
chained_evaluation_3: {
options = {
collapse_vars: true,
evaluate: 10,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = "long piece of string";
(function() {
var b = a, c;
c = f(b);
c.bar = b;
})();
})();
}
expect: {
(function() {
(function() {
f("long piece of string").bar = "long piece of string";
})();
})();
}
}

View File

@@ -1,4 +1,3 @@
issue_1639_1: { issue_1639_1: {
options = { options = {
booleans: true, booleans: true,
@@ -12,7 +11,6 @@ issue_1639_1: {
} }
input: { input: {
var a = 100, b = 10; var a = 100, b = 10;
var L1 = 5; var L1 = 5;
while (--L1 > 0) { while (--L1 > 0) {
if ((--b), false) { if ((--b), false) {
@@ -21,7 +19,6 @@ issue_1639_1: {
} }
} }
} }
console.log(a, b); console.log(a, b);
} }
expect: { expect: {
@@ -29,7 +26,7 @@ issue_1639_1: {
if (--b, 0) var ignore = 0; if (--b, 0) var ignore = 0;
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "100 6"
} }
issue_1639_2: { issue_1639_2: {
@@ -44,25 +41,23 @@ issue_1639_2: {
} }
input: { input: {
var a = 100, b = 10; var a = 100, b = 10;
function f19() { function f19() {
if (++a, false) if (++a, false)
if (a) if (a)
if (++a); if (++a);
} }
f19(); f19();
console.log(a, b); console.log(a, b);
} }
expect: { expect: {
var a = 100, b = 10; var a = 100, b = 10;
function f19() { function f19() {
++a, 0; ++a, 1;
} }
f19(), f19(),
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "101 10"
} }
issue_1639_3: { issue_1639_3: {
@@ -84,5 +79,5 @@ issue_1639_3: {
a++, a++,
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "101 10"
} }

View File

@@ -366,7 +366,7 @@ mangle_catch_redef_3: {
console.log(o); console.log(o);
} }
expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);' expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
expect_stdout: "PASS" expect_stdout: true
} }
mangle_catch_redef_3_toplevel: { mangle_catch_redef_3_toplevel: {
@@ -389,10 +389,10 @@ mangle_catch_redef_3_toplevel: {
console.log(o); console.log(o);
} }
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);' expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: "PASS" expect_stdout: true
} }
mangle_catch_redef_ie8_3: { mangle_catch_redef_3_ie8: {
mangle = { mangle = {
ie8: true, ie8: true,
toplevel: false, toplevel: false,
@@ -412,7 +412,7 @@ mangle_catch_redef_ie8_3: {
console.log(o); console.log(o);
} }
expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);' expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
expect_stdout: "PASS" expect_stdout: true
} }
mangle_catch_redef_3_ie8_toplevel: { mangle_catch_redef_3_ie8_toplevel: {
@@ -435,5 +435,5 @@ mangle_catch_redef_3_ie8_toplevel: {
console.log(o); console.log(o);
} }
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);' expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: "PASS" expect_stdout: true
} }

View File

@@ -46,7 +46,7 @@ mangle_props: {
obj[1/0], obj[1/0],
obj["Infinity"], obj["Infinity"],
obj[-1/0], obj[-1/0],
obj[-1/0], obj[-(1/0)],
obj["-Infinity"], obj["-Infinity"],
obj[null], obj[null],
obj["null"] obj["null"]

View File

@@ -125,8 +125,8 @@ label_do: {
label_while: { label_while: {
options = { options = {
evaluate: true,
dead_code: true, dead_code: true,
evaluate: true,
loops: true, loops: true,
} }
input: { input: {

View File

@@ -1,6 +1,8 @@
do_not_update_lhs: { do_not_update_lhs: {
options = { options = {
global_defs: { DEBUG: 0 } global_defs: {
DEBUG: 0,
},
} }
input: { input: {
DEBUG++; DEBUG++;
@@ -16,7 +18,9 @@ do_not_update_lhs: {
do_update_rhs: { do_update_rhs: {
options = { options = {
global_defs: { DEBUG: 0 } global_defs: {
DEBUG: 0,
},
} }
input: { input: {
MY_DEBUG = DEBUG; MY_DEBUG = DEBUG;
@@ -35,7 +39,7 @@ mixed: {
DEBUG: 0, DEBUG: 0,
ENV: 1, ENV: 1,
FOO: 2, FOO: 2,
} },
} }
input: { input: {
var ENV = 3; var ENV = 3;
@@ -60,11 +64,11 @@ mixed: {
x = 0; x = 0;
} }
expect_warnings: [ expect_warnings: [
'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,12]', "WARN: global_defs ENV redefined [test/compress/issue-208.js:1,12]",
'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]', "WARN: global_defs FOO redefined [test/compress/issue-208.js:2,12]",
'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]', "WARN: global_defs FOO redefined [test/compress/issue-208.js:4,10]",
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]', "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:5,8]",
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:46,8]', "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:6,8]",
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:47,8]', "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:7,8]",
] ]
} }

View File

@@ -1,5 +1,7 @@
return_with_no_value_in_if_body: { return_with_no_value_in_if_body: {
options = { conditionals: true }; options = {
conditionals: true,
}
input: { input: {
function foo(bar) { function foo(bar) {
if (bar) { if (bar) {

View File

@@ -1,5 +1,7 @@
issue_267: { issue_267: {
options = { comparisons: true }; options = {
comparisons: true,
}
input: { input: {
x = a % b / b * c * 2; x = a % b / b * c * 2;
x = a % b * 2 x = a % b * 2

View File

@@ -1,7 +1,10 @@
issue_269_1: { issue_269_1: {
options = {unsafe: true}; options = {
unsafe: true,
}
input: { input: {
f( var x = {};
console.log(
String(x), String(x),
Number(x), Number(x),
Boolean(x), Boolean(x),
@@ -12,32 +15,42 @@ issue_269_1: {
); );
} }
expect: { expect: {
f( var x = {};
x + '', +x, !!x, console.log(
'', 0, false x + "", +x, !!x,
"", 0, false
); );
} }
expect_stdout: true
} }
issue_269_dangers: { issue_269_dangers: {
options = {unsafe: true}; options = {
unsafe: true,
}
input: { input: {
f( var x = {};
console.log(
String(x, x), String(x, x),
Number(x, x), Number(x, x),
Boolean(x, x) Boolean(x, x)
); );
} }
expect: { expect: {
f(String(x, x), Number(x, x), Boolean(x, x)); var x = {};
console.log(String(x, x), Number(x, x), Boolean(x, x));
} }
expect_stdout: true
} }
issue_269_in_scope: { issue_269_in_scope: {
options = {unsafe: true}; options = {
unsafe: true,
}
input: { input: {
var String, Number, Boolean; var String, Number, Boolean;
f( var x = {};
console.log(
String(x), String(x),
Number(x, x), Number(x, x),
Boolean(x) Boolean(x)
@@ -45,24 +58,32 @@ issue_269_in_scope: {
} }
expect: { expect: {
var String, Number, Boolean; var String, Number, Boolean;
f(String(x), Number(x, x), Boolean(x)); var x = {};
console.log(String(x), Number(x, x), Boolean(x));
} }
expect_stdout: true
} }
strings_concat: { strings_concat: {
options = {unsafe: true}; options = {
strings: true,
unsafe: true,
}
input: { input: {
f( var x = {};
String(x + 'str'), console.log(
String('str' + x) String(x + "str"),
String("str" + x)
); );
} }
expect: { expect: {
f( var x = {};
x + 'str', console.log(
'str' + x x + "str",
"str" + x
); );
} }
expect_stdout: true
} }
regexp: { regexp: {
@@ -85,6 +106,6 @@ regexp: {
RegExp("should", "fail"); RegExp("should", "fail");
} }
expect_warnings: [ expect_warnings: [
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:78,2]', 'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,8]',
] ]
} }

View File

@@ -26,7 +26,7 @@ warn: {
}().length); }().length);
} }
expect_warnings: [ expect_warnings: [
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:17,19]", "WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:17,19]", "WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
] ]
} }

View File

@@ -186,7 +186,7 @@ negate_iife_5_off: {
inline: true, inline: true,
negate_iife: false, negate_iife: false,
sequences: true, sequences: true,
}; }
input: { input: {
if ((function(){ return t })()) { if ((function(){ return t })()) {
foo(true); foo(true);
@@ -245,7 +245,7 @@ negate_iife_issue_1073: {
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
unused: true, unused: true,
}; }
input: { input: {
new (function(a) { new (function(a) {
return function Foo() { return function Foo() {
@@ -273,7 +273,7 @@ issue_1288_side_effects: {
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
}; }
input: { input: {
if (w) ; if (w) ;
else { else {
@@ -399,7 +399,7 @@ wrap_iife_in_expression: {
wrap_iife: true, wrap_iife: true,
} }
input: { input: {
foo = (function () { foo = (function() {
return bar(); return bar();
})(); })();
} }

128
test/compress/issue-3768.js Normal file
View File

@@ -0,0 +1,128 @@
mangle: {
mangle = {
toplevel: true,
}
input: {
var e = eval, x = 42;
(function() {
console.log(e("typeof x"));
})();
}
expect: {
var e = eval, x = 42;
(function() {
console.log(e("typeof x"));
})();
}
expect_stdout: true
}
compress: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
console.log(function() {
var a = 42;
return eval("typeof a");
}(), function(e) {
var a = null;
return e("typeof a");
}(eval), function(eval) {
var a = false;
return eval("typeof a");
}(eval), function(f) {
var a = "STRING";
var eval = f;
return eval("typeof a");
}(eval), function(g) {
var a = eval;
function eval() {
return g;
}
return eval()("typeof a");
}(eval));
}
expect: {
console.log(function() {
var a = 42;
return eval("typeof a");
}(), (0, eval)("typeof a"), function(eval) {
var a = false;
return eval("typeof a");
}(eval), function(f) {
var a = "STRING";
var eval = f;
return eval("typeof a");
}(eval), function(g) {
var a = eval;
function eval() {
return g;
}
return eval()("typeof a");
}(eval));
}
expect_stdout: "number undefined boolean string undefined"
}
call_arg_1: {
mangle = {
toplevel: true,
}
input: {
var z = "foo";
(function() {
var z = false;
(function(e) {
var z = 42;
e("console.log(typeof z)");
})(eval);
})();
}
expect: {
var z = "foo";
(function() {
var o = false;
(function(o) {
var a = 42;
o("console.log(typeof z)");
})(eval);
})();
}
expect_stdout: true
}
call_arg_2: {
mangle = {
toplevel: true,
}
input: {
function eval() {
console.log("PASS");
}
var z = "foo";
(function() {
var z = false;
(function(e) {
var z = 42;
e("console.log(typeof z)");
})(eval);
})();
}
expect: {
function n() {
console.log("PASS");
}
var o = "foo";
(function() {
var o = false;
(function(o) {
var n = 42;
o("console.log(typeof z)");
})(n);
})();
}
expect_stdout: "PASS"
}

View File

@@ -1,5 +1,7 @@
issue_44_valid_ast_1: { issue_44_valid_ast_1: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function a(b) { function a(b) {
for (var i = 0, e = b.qoo(); ; i++) {} for (var i = 0, e = b.qoo(); ; i++) {}
@@ -14,7 +16,9 @@ issue_44_valid_ast_1: {
} }
issue_44_valid_ast_2: { issue_44_valid_ast_2: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function a(b) { function a(b) {
if (foo) for (var i = 0, e = b.qoo(); ; i++) {} if (foo) for (var i = 0, e = b.qoo(); ; i++) {}

View File

@@ -1,8 +1,8 @@
keep_continue: { keep_continue: {
options = { options = {
dead_code: true, dead_code: true,
evaluate: true evaluate: true,
}; }
input: { input: {
while (a) { while (a) {
if (b) { if (b) {

View File

@@ -1,5 +1,5 @@
NaN_and_Infinity_must_have_parens: { NaN_and_Infinity_must_have_parens: {
options = {}; options = {}
input: { input: {
Infinity.toString(); Infinity.toString();
NaN.toString(); NaN.toString();
@@ -11,7 +11,7 @@ NaN_and_Infinity_must_have_parens: {
} }
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: { NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
options = {}; options = {}
input: { input: {
var Infinity, NaN; var Infinity, NaN;
Infinity.toString(); Infinity.toString();

View File

@@ -1,8 +1,8 @@
issue_611: { issue_611: {
options = { options = {
sequences: true, sequences: true,
side_effects: true side_effects: true,
}; }
input: { input: {
define(function() { define(function() {
function fn() {} function fn() {}

View File

@@ -1,9 +1,9 @@
wrongly_optimized: { wrongly_optimized: {
options = { options = {
conditionals: true,
booleans: true, booleans: true,
evaluate: true conditionals: true,
}; evaluate: true,
}
input: { input: {
function func() { function func() {
foo(); foo();
@@ -16,7 +16,6 @@ wrongly_optimized: {
function func() { function func() {
foo(); foo();
} }
// TODO: optimize to `func(), bar()` func(), 1, bar();
(func(), 1) && bar();
} }
} }

View File

@@ -21,19 +21,19 @@ cond_5: {
} }
} }
expect: { expect: {
some_condition() && some_other_condition() ? do_something() : alternate(); (some_condition() && some_other_condition() ? do_something : alternate)();
if (some_condition() && some_other_condition()) do_something(); if (some_condition() && some_other_condition()) do_something();
} }
} }
dead_code_const_annotation_regex: { dead_code_const_annotation_regex: {
options = { options = {
booleans : true, booleans: true,
conditionals : true, conditionals: true,
dead_code : true, dead_code: true,
evaluate : true, evaluate: true,
expression : true, expression: true,
loops : true, loops: true,
} }
input: { input: {
var unused; var unused;
@@ -82,8 +82,9 @@ drop_value: {
wrongly_optimized: { wrongly_optimized: {
options = { options = {
conditionals: true,
booleans: true, booleans: true,
conditionals: true,
dead_code: true,
evaluate: true, evaluate: true,
expression: true, expression: true,
} }
@@ -99,8 +100,8 @@ wrongly_optimized: {
function func() { function func() {
foo(); foo();
} }
// TODO: optimize to `func(), bar()` func(), 1;
if (func(), 1) bar(); bar();
} }
} }
@@ -195,7 +196,7 @@ negate_iife_5_off: {
expression: true, expression: true,
negate_iife: false, negate_iife: false,
sequences: true, sequences: true,
}; }
input: { input: {
if ((function(){ return t })()) { if ((function(){ return t })()) {
foo(true); foo(true);
@@ -248,7 +249,9 @@ issue_1254_negate_iife_nested: {
conditional: { conditional: {
options = { options = {
expression: true, expression: true,
pure_funcs: [ "pure" ], pure_funcs: [
"pure"
],
side_effects: true, side_effects: true,
} }
input: { input: {

View File

@@ -1,7 +1,7 @@
negate_booleans_1: { negate_booleans_1: {
options = { options = {
comparisons: true comparisons: true,
}; }
input: { input: {
var a = !a || !b || !c || !d || !e || !f; var a = !a || !b || !c || !d || !e || !f;
} }
@@ -12,8 +12,8 @@ negate_booleans_1: {
negate_booleans_2: { negate_booleans_2: {
options = { options = {
comparisons: true comparisons: true,
}; }
input: { input: {
var match = !x && // should not touch this one var match = !x && // should not touch this one
(!z || c) && (!z || c) &&

View File

@@ -1,5 +1,7 @@
remove_redundant_sequence_items: { remove_sequence: {
options = { side_effects: true }; options = {
side_effects: true,
}
input: { input: {
(0, 1, eval)(); (0, 1, eval)();
(0, 1, logThis)(); (0, 1, logThis)();
@@ -12,14 +14,36 @@ remove_redundant_sequence_items: {
} }
} }
dont_remove_this_binding_sequence: { remove_redundant_sequence_items: {
options = { side_effects: true }; options = {
side_effects: true,
}
input: { input: {
(0, eval)(); "use strict";
(0, logThis)(); (0, 1, eval)();
(0, _decorators.logThis)(); (0, 1, logThis)();
(0, 1, _decorators.logThis)();
} }
expect: { expect: {
"use strict";
(0, eval)();
logThis();
(0, _decorators.logThis)();
}
}
dont_remove_this_binding_sequence: {
options = {
side_effects: true,
}
input: {
"use strict";
(0, eval)();
(0, logThis)();
(0, _decorators.logThis)();
}
expect: {
"use strict";
(0, eval)(); (0, eval)();
logThis(); logThis();
(0, _decorators.logThis)(); (0, _decorators.logThis)();

View File

@@ -2,25 +2,25 @@ dont_mangle_arguments: {
mangle = { mangle = {
}; };
options = { options = {
sequences : true, booleans: true,
properties : true, comparisons: true,
dead_code : true, conditionals: true,
drop_debugger : true, dead_code: true,
conditionals : true, drop_debugger: true,
comparisons : true, evaluate: true,
evaluate : true, hoist_funs: true,
booleans : true, hoist_vars: true,
loops : true, if_return: true,
unused : true, join_vars: true,
hoist_funs : true, keep_fargs: true,
keep_fargs : true, keep_fnames: false,
keep_fnames : false, loops: true,
hoist_vars : true, negate_iife: false,
if_return : true, properties: true,
join_vars : true, sequences: true,
side_effects : true, side_effects: true,
negate_iife : false unused: true,
}; }
input: { input: {
(function(){ (function(){
var arguments = arguments, not_arguments = 9; var arguments = arguments, not_arguments = 9;

View File

@@ -1,8 +1,8 @@
keep_var_for_in: { keep_var_for_in: {
options = { options = {
hoist_vars: true, hoist_vars: true,
unused: true unused: true,
}; }
input: { input: {
(function(obj){ (function(obj){
var foo = 5; var foo = 5;

View File

@@ -3,8 +3,9 @@ this_binding_conditionals: {
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
side_effects: true, side_effects: true,
}; }
input: { input: {
"use strict";
(1 && a)(); (1 && a)();
(0 || a)(); (0 || a)();
(0 || 1 && a)(); (0 || 1 && a)();
@@ -26,6 +27,7 @@ this_binding_conditionals: {
(1 ? eval : 0)(); (1 ? eval : 0)();
} }
expect: { expect: {
"use strict";
a(); a();
a(); a();
a(); a();
@@ -51,49 +53,111 @@ this_binding_conditionals: {
this_binding_collapse_vars: { this_binding_collapse_vars: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: true,
unused: true, unused: true,
}; }
input: { input: {
function f() {
"use strict";
var c = a; c(); var c = a; c();
var d = a.b; d(); var d = a.b; d();
var e = eval; e(); var e = eval; e();
} }
}
expect: { expect: {
function f() {
"use strict";
a(); a();
(0, a.b)(); (0, a.b)();
(0, eval)(); (0, eval)();
} }
}
} }
this_binding_side_effects: { this_binding_side_effects: {
options = { options = {
side_effects : true side_effects: true,
}; }
input: { input: {
(function (foo) { (function(foo) {
(0, foo)(); (0, foo)();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); (0, eval)("console.log(foo);");
}()); }());
(function (foo) { (function(foo) {
"use strict";
(0, foo)();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console; var eval = console;
(0, foo)(); (0, foo)();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); (0, eval)("console.log(foo);");
}()); }());
} }
expect: { expect: {
(function (foo) { (function(foo) {
foo(); foo();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); (0, eval)("console.log(foo);");
}()); }());
(function (foo) { (function(foo) {
"use strict";
foo();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console; var eval = console;
foo(); foo();
(0, foo.bar)(); (0, foo.bar)();
(0, eval)('console.log(foo);'); eval("console.log(foo);");
}()); }());
} }
} }
this_binding_sequences: {
options = {
sequences: true,
side_effects: true,
}
input: {
console.log(typeof function() {
return eval("this");
}());
console.log(typeof function() {
"use strict";
return eval("this");
}());
console.log(typeof function() {
return (0, eval)("this");
}());
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect: {
console.log(typeof function() {
return eval("this");
}()),
console.log(typeof function() {
"use strict";
return eval("this");
}()),
console.log(typeof function() {
return (0, eval)("this");
}()),
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect_stdout: [
"object",
"undefined",
"object",
"object",
]
}

View File

@@ -1,9 +1,21 @@
eval_collapse_vars: { eval_collapse_vars: {
options = { options = {
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true, booleans: true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, collapse_vars: true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true comparisons: true,
}; conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
properties: true,
sequences: false,
side_effects: true,
unused: true,
}
input: { input: {
function f1() { function f1() {
var e = 7; var e = 7;
@@ -46,7 +58,10 @@ eval_collapse_vars: {
} }
eval_unused: { eval_unused: {
options = { unused: true, keep_fargs: false }; options = {
keep_fargs: false,
unused: true,
}
input: { input: {
function f1(a, eval, c, d, e) { function f1(a, eval, c, d, e) {
return a('c') + eval; return a('c') + eval;

View File

@@ -1,8 +1,19 @@
issue979_reported: { issue979_reported: {
options = { options = {
sequences:true, properties:true, dead_code:true, conditionals:true, booleans: true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons: true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
} }
input: { input: {
function f1() { function f1() {
@@ -30,9 +41,20 @@ issue979_reported: {
issue979_test_negated_is_best: { issue979_test_negated_is_best: {
options = { options = {
sequences:true, properties:true, dead_code:true, conditionals:true, booleans: true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons: true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
} }
input: { input: {
function f3() { function f3() {

1457
test/compress/keep_fargs.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,9 @@
labels_1: { labels_1: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
out: { out: {
if (foo) break out; if (foo) break out;
@@ -13,7 +17,11 @@ labels_1: {
} }
labels_2: { labels_2: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
out: { out: {
if (foo) print("stuff"); if (foo) print("stuff");
@@ -30,7 +38,11 @@ labels_2: {
} }
labels_3: { labels_3: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
for (var i = 0; i < 5; ++i) { for (var i = 0; i < 5; ++i) {
if (i < 3) continue; if (i < 3) continue;
@@ -45,7 +57,11 @@ labels_3: {
} }
labels_4: { labels_4: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
out: for (var i = 0; i < 5; ++i) { out: for (var i = 0; i < 5; ++i) {
if (i < 3) continue out; if (i < 3) continue out;
@@ -60,7 +76,11 @@ labels_4: {
} }
labels_5: { labels_5: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
// should keep the break-s in the following // should keep the break-s in the following
input: { input: {
while (foo) { while (foo) {
@@ -92,7 +112,11 @@ labels_6: {
} }
labels_7: { labels_7: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
while (foo) { while (foo) {
x(); x();
@@ -109,7 +133,11 @@ labels_7: {
} }
labels_8: { labels_8: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
while (foo) { while (foo) {
x(); x();
@@ -127,7 +155,11 @@ labels_8: {
} }
labels_9: { labels_9: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
out: while (foo) { out: while (foo) {
x(); x();
@@ -146,7 +178,11 @@ labels_9: {
} }
labels_10: { labels_10: {
options = { if_return: true, conditionals: true, dead_code: true }; options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: { input: {
out: while (foo) { out: while (foo) {
x(); x();

View File

@@ -1,37 +1,45 @@
while_becomes_for: { while_becomes_for: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
while (foo()) bar(); while (foo()) bar();
} }
expect: { expect: {
for (; foo(); ) bar(); for (;foo();) bar();
} }
} }
drop_if_break_1: { drop_if_break_1: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;;) for (;;)
if (foo()) break; if (foo()) break;
} }
expect: { expect: {
for (; !foo();); for (;!foo(););
} }
} }
drop_if_break_2: { drop_if_break_2: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;bar();) for (;bar();)
if (foo()) break; if (foo()) break;
} }
expect: { expect: {
for (; bar() && !foo();); for (;bar() && !foo(););
} }
} }
drop_if_break_3: { drop_if_break_3: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;bar();) { for (;bar();) {
if (foo()) break; if (foo()) break;
@@ -48,7 +56,10 @@ drop_if_break_3: {
} }
drop_if_break_4: { drop_if_break_4: {
options = { loops: true, sequences: true }; options = {
loops: true,
sequences: true,
}
input: { input: {
for (;bar();) { for (;bar();) {
x(); x();
@@ -59,22 +70,26 @@ drop_if_break_4: {
} }
} }
expect: { expect: {
for (; bar() && (x(), y(), !foo());) z(), k(); for (;bar() && (x(), y(), !foo());) z(), k();
} }
} }
drop_if_else_break_1: { drop_if_else_break_1: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;;) if (foo()) bar(); else break; for (;;) if (foo()) bar(); else break;
} }
expect: { expect: {
for (; foo(); ) bar(); for (;foo();) bar();
} }
} }
drop_if_else_break_2: { drop_if_else_break_2: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;bar();) { for (;bar();) {
if (foo()) baz(); if (foo()) baz();
@@ -82,12 +97,14 @@ drop_if_else_break_2: {
} }
} }
expect: { expect: {
for (; bar() && foo();) baz(); for (;bar() && foo();) baz();
} }
} }
drop_if_else_break_3: { drop_if_else_break_3: {
options = { loops: true }; options = {
loops: true,
}
input: { input: {
for (;bar();) { for (;bar();) {
if (foo()) baz(); if (foo()) baz();
@@ -97,7 +114,7 @@ drop_if_else_break_3: {
} }
} }
expect: { expect: {
for (; bar() && foo();) { for (;bar() && foo();) {
baz(); baz();
stuff1(); stuff1();
stuff2(); stuff2();
@@ -106,7 +123,10 @@ drop_if_else_break_3: {
} }
drop_if_else_break_4: { drop_if_else_break_4: {
options = { loops: true, sequences: true }; options = {
loops: true,
sequences: true,
}
input: { input: {
for (;bar();) { for (;bar();) {
x(); x();
@@ -118,12 +138,14 @@ drop_if_else_break_4: {
} }
} }
expect: { expect: {
for (; bar() && (x(), y(), foo());) baz(), z(), k(); for (;bar() && (x(), y(), foo());) baz(), z(), k();
} }
} }
parse_do_while_with_semicolon: { parse_do_while_with_semicolon: {
options = { loops: false }; options = {
loops: false,
}
input: { input: {
do { do {
x(); x();
@@ -135,7 +157,9 @@ parse_do_while_with_semicolon: {
} }
parse_do_while_without_semicolon: { parse_do_while_without_semicolon: {
options = { loops: false }; options = {
loops: false,
}
input: { input: {
do { do {
x(); x();
@@ -153,7 +177,7 @@ evaluate: {
loops: true, loops: true,
passes: 2, passes: 2,
side_effects: true, side_effects: true,
}; }
input: { input: {
while (true) { while (true) {
a(); a();
@@ -457,7 +481,7 @@ init_side_effects: {
options = { options = {
loops: true, loops: true,
side_effects: true, side_effects: true,
}; }
input: { input: {
for (function() {}(), i = 0; i < 5; i++) console.log(i); for (function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 10; i++) console.log(i); for (function() {}(); i < 10; i++) console.log(i);
@@ -499,13 +523,13 @@ issue_2740_1: {
loops: true, loops: true,
} }
input: { input: {
for (; ; ) break; for (;;) break;
for (a(); ; ) break; for (a();;) break;
for (; b(); ) break; for (;b();) break;
for (c(); d(); ) break; for (c(); d();) break;
for (; ; e()) break; for (;;e()) break;
for (f(); ; g()) break; for (f();; g()) break;
for (; h(); i()) break; for (;h(); i()) break;
for (j(); k(); l()) break; for (j(); k(); l()) break;
} }
expect: { expect: {
@@ -550,9 +574,11 @@ issue_2740_3: {
console.log(x, y); console.log(x, y);
} }
expect: { expect: {
L1: for (var x = 0; x < 3; x++) L1: for (var x = 0; x < 3; x++) {
for (var y = 0; y < 2; y++) var y = 0;
if (y < 2)
break L1; break L1;
}
console.log(x, y); console.log(x, y);
} }
expect_stdout: "0 0" expect_stdout: "0 0"
@@ -622,3 +648,282 @@ issue_2904: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_3371: {
options = {
functions: true,
join_vars: true,
loops: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = function() {
console.log("PASS");
};
while (a());
})();
}
expect: {
(function() {
function a() {
console.log("PASS");
}
for (;a(););
})();
}
expect_stdout: "PASS"
}
step: {
options = {
loops: true,
side_effects: true,
}
input: {
for (var i = 0; i < 42; "foo", i++, "bar");
console.log(i);
}
expect: {
for (var i = 0; i < 42; i++);
console.log(i);
}
expect_stdout: "42"
}
empty_for_in: {
options = {
loops: true,
toplevel: true,
unused: true,
}
input: {
for (var a in [ 1, 2, 3 ]) {
var b = a + 1;
}
}
expect: {}
expect_warnings: [
"WARN: Dropping unused variable b [test/compress/loops.js:2,16]",
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
]
}
empty_for_in_used: {
options = {
loops: true,
toplevel: true,
unused: true,
}
input: {
for (var a in [ 1, 2, 3 ]) {
var b = a + 1;
}
console.log(a);
}
expect: {
for (var a in [ 1, 2, 3 ]);
console.log(a);
}
expect_stdout: "2"
expect_warnings: [
"WARN: Dropping unused variable b [test/compress/loops.js:2,16]",
]
}
empty_for_in_side_effects: {
options = {
loops: true,
toplevel: true,
unused: true,
}
input: {
for (var a in {
foo: console.log("PASS")
}) {
var b = a + "bar";
}
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
expect_warnings: [
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
]
}
issue_3631_1: {
options = {
dead_code: true,
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
}
input: {
var c = 0;
L: do {
for (;;) continue L;
var b = 1;
} while (b && c++);
console.log(c);
}
expect: {
var c = 0;
do {
var b;
} while (b && c++);
console.log(c);
}
expect_stdout: "0"
}
issue_3631_2: {
options = {
dead_code: true,
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
}
input: {
L: for (var a = 1; a--; console.log(b)) {
for (;;) continue L;
var b = "FAIL";
}
}
expect: {
for (var a = 1; a--; console.log(b))
var b;
}
expect_stdout: "undefined"
}
loop_if_break: {
options = {
dead_code: true,
loops: true,
}
input: {
function f(a, b) {
try {
while (a) {
if (b) {
break;
var c = 42;
console.log(c);
} else {
var d = false;
throw d;
}
}
} catch (e) {
console.log("E:", e);
}
console.log(a, b, c, d);
}
f(0, 0);
f(0, 1);
f(1, 0);
f(1, 1);
}
expect: {
function f(a, b) {
try {
for (;a && !b;) {
var d = false;
throw d;
var c;
}
} catch (e) {
console.log("E:", e);
}
console.log(a, b, c, d);
}
f(0, 0);
f(0, 1);
f(1, 0);
f(1, 1);
}
expect_stdout: [
"0 0 undefined undefined",
"0 1 undefined undefined",
"E: false",
"1 0 undefined false",
"1 1 undefined undefined",
]
}
loop_return: {
options = {
dead_code: true,
loops: true,
}
input: {
function f(a) {
while (a) return 42;
return "foo";
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
if (a) return 42;
return "foo";
}
console.log(f(0), f(1));
}
expect_stdout: "foo 42"
}
issue_3634_1: {
options = {
loops: true,
}
input: {
var b = 0;
L: while (++b < 2)
while (1)
if (b) break L;
console.log(b);
}
expect: {
var b = 0;
L: for (;++b < 2;)
for (;1;)
if (b) break L;
console.log(b);
}
expect_stdout: "1"
}
issue_3634_2: {
options = {
loops: true,
}
input: {
var b = 0;
L: while (++b < 2)
while (1)
if (!b)
continue L;
else
break L;
console.log(b);
}
expect: {
var b = 0;
L: for (;++b < 2;)
for (;1;)
if (!b)
continue L;
else
break L;
console.log(b);
}
expect_stdout: "1"
}

View File

@@ -8,14 +8,14 @@ too_short: {
} }
} }
expect_exact: [ expect_exact: [
'function f(a){', "function f(",
'return{', "a){return{",
'c:42,', "c:42,d:a(",
'd:a(),', '),e:"foo"}',
'e:"foo"}}', "}",
] ]
expect_warnings: [ expect_warnings: [
"WARN: Output exceeds 10 characters" "WARN: Output exceeds 10 characters",
] ]
} }
@@ -29,11 +29,25 @@ just_enough: {
} }
} }
expect_exact: [ expect_exact: [
'function f(a){', "function f(a){",
'return{c:42,', "return{c:42,",
'd:a(),e:"foo"}', 'd:a(),e:"foo"}',
'}', "}",
]
expect_warnings: [
] ]
expect_warnings: []
}
issue_304: {
beautify = {
max_line_len: 10,
}
input: {
var a = 0, b = 0, c = 0, d = 0, e = 0;
}
expect_exact: [
"var a=0,",
"b=0,c=0,",
"d=0,e=0;",
]
expect_warnings: []
} }

View File

@@ -1,7 +1,7 @@
negate_iife_1: { negate_iife_1: {
options = { options = {
negate_iife: true negate_iife: true,
}; }
input: { input: {
(function(){ stuff() })(); (function(){ stuff() })();
} }
@@ -13,7 +13,7 @@ negate_iife_1: {
negate_iife_1_off: { negate_iife_1_off: {
options = { options = {
negate_iife: false, negate_iife: false,
}; }
input: { input: {
(function(){ stuff() })(); (function(){ stuff() })();
} }
@@ -24,7 +24,7 @@ negate_iife_2: {
options = { options = {
inline: true, inline: true,
negate_iife: true, negate_iife: true,
}; }
input: { input: {
(function(){ return {} })().x = 10; (function(){ return {} })().x = 10;
} }
@@ -45,9 +45,9 @@ negate_iife_2_side_effects: {
negate_iife_3: { negate_iife_3: {
options = { options = {
conditionals: true,
negate_iife: true, negate_iife: true,
conditionals: true }
};
input: { input: {
(function(){ return t })() ? console.log(true) : console.log(false); (function(){ return t })() ? console.log(true) : console.log(false);
} }
@@ -88,9 +88,9 @@ negate_iife_3_side_effects: {
negate_iife_3_off: { negate_iife_3_off: {
options = { options = {
negate_iife: false,
conditionals: true, conditionals: true,
}; negate_iife: false,
}
input: { input: {
(function(){ return t })() ? console.log(true) : console.log(false); (function(){ return t })() ? console.log(true) : console.log(false);
} }
@@ -117,10 +117,10 @@ negate_iife_3_off_evaluate: {
negate_iife_4: { negate_iife_4: {
options = { options = {
negate_iife: true,
conditionals: true, conditionals: true,
sequences: true negate_iife: true,
}; sequences: true,
}
input: { input: {
(function(){ return t })() ? console.log(true) : console.log(false); (function(){ return t })() ? console.log(true) : console.log(false);
(function(){ (function(){
@@ -136,11 +136,11 @@ negate_iife_4: {
sequence_off: { sequence_off: {
options = { options = {
negate_iife: false,
conditionals: true, conditionals: true,
sequences: true, negate_iife: false,
passes: 2, passes: 2,
}; sequences: true,
}
input: { input: {
function f() { function f() {
(function(){ return t })() ? console.log(true) : console.log(false); (function(){ return t })() ? console.log(true) : console.log(false);
@@ -171,10 +171,10 @@ sequence_off: {
negate_iife_5: { negate_iife_5: {
options = { options = {
conditionals: true,
negate_iife: true, negate_iife: true,
sequences: true, sequences: true,
conditionals: true, }
};
input: { input: {
if ((function(){ return t })()) { if ((function(){ return t })()) {
foo(true); foo(true);
@@ -194,10 +194,10 @@ negate_iife_5: {
negate_iife_5_off: { negate_iife_5_off: {
options = { options = {
conditionals: true,
negate_iife: false, negate_iife: false,
sequences: true, sequences: true,
conditionals: true, }
};
input: { input: {
if ((function(){ return t })()) { if ((function(){ return t })()) {
foo(true); foo(true);
@@ -217,10 +217,10 @@ negate_iife_5_off: {
negate_iife_nested: { negate_iife_nested: {
options = { options = {
conditionals: true,
negate_iife: true, negate_iife: true,
sequences: true, sequences: true,
conditionals: true, }
};
input: { input: {
function Foo(f) { function Foo(f) {
this.f = f; this.f = f;
@@ -250,10 +250,10 @@ negate_iife_nested: {
negate_iife_nested_off: { negate_iife_nested_off: {
options = { options = {
conditionals: true,
negate_iife: false, negate_iife: false,
sequences: true, sequences: true,
conditionals: true, }
};
input: { input: {
function Foo(f) { function Foo(f) {
this.f = f; this.f = f;
@@ -283,10 +283,10 @@ negate_iife_nested_off: {
negate_iife_issue_1073: { negate_iife_issue_1073: {
options = { options = {
conditionals: true,
negate_iife: true, negate_iife: true,
sequences: true, sequences: true,
conditionals: true, }
};
input: { input: {
new (function(a) { new (function(a) {
return function Foo() { return function Foo() {
@@ -356,7 +356,7 @@ issue_1288: {
conditionals: true, conditionals: true,
negate_iife: true, negate_iife: true,
side_effects: false, side_effects: false,
}; }
input: { input: {
if (w) ; if (w) ;
else { else {

View File

@@ -36,7 +36,9 @@ new_statements_3: {
} }
new_with_rewritten_true_value: { new_with_rewritten_true_value: {
options = { booleans: true } options = {
booleans: true,
}
input: { input: {
new true; new true;
} }

File diff suppressed because it is too large Load Diff

223
test/compress/objects.js Normal file
View File

@@ -0,0 +1,223 @@
duplicate_key: {
options = {
objects: true,
side_effects: true,
}
input: {
var o = {
a: 1,
b: 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: 3,
b: 2,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
}
duplicate_key_strict: {
options = {
objects: true,
side_effects: true,
}
input: {
"use strict";
var o = {
a: 1,
b: 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
"use strict";
var o = {
a: 1,
b: 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: true
}
duplicate_key_side_effect: {
options = {
objects: true,
side_effects: true,
}
input: {
var o = {
a: 1,
b: o = 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: 1,
b: o = 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
}
duplicate_key_with_accessor: {
options = {
objects: true,
side_effects: true,
}
input: {
[
{
a: 0,
b: 1,
a: 2,
set b(v) {},
},
{
a: 3,
b: 4,
get a() {
return 5;
},
a: 6,
b: 7,
a: 8,
b: 9,
},
].forEach(function(o) {
for (var k in o)
console.log(k, o[k]);
});
}
expect: {
[
{
a: 2,
b: 1,
set b(v) {},
},
{
a: 3,
b: 4,
get a() {
return 5;
},
a: 8,
b: 9,
},
].forEach(function(o) {
for (var k in o)
console.log(k, o[k]);
});
}
expect_stdout: true
}
unsafe_object_repeated: {
options = {
evaluate: true,
objects: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
}
input: {
var o = { a: { b: 1 }, a: 1 };
console.log(
o + 1,
o.a + 1,
o.b + 1,
o.a.b + 1
);
}
expect: {
var o = { a: 1 };
console.log(
o + 1,
2,
o.b + 1,
NaN
);
}
expect_stdout: true
}
numeric_literal: {
options = {
objects: true,
side_effects: true,
}
mangle = {
properties: true,
}
beautify = {
beautify: true,
}
input: {
var obj = {
0: 0,
"-0": 1,
42: 2,
"42": 3,
0x25: 4,
"0x25": 5,
1E42: 6,
"1E42": 7,
"1e+42": 8,
};
console.log(obj[-0], obj[-""], obj["-0"]);
console.log(obj[42], obj["42"]);
console.log(obj[0x25], obj["0x25"], obj[37], obj["37"]);
console.log(obj[1E42], obj["1E42"], obj["1e+42"]);
}
expect_exact: [
'var obj = {',
' 0: 0,',
' "-0": 1,',
' 42: 3,',
' 37: 4,',
' o: 5,',
' 1e42: 8,',
' b: 7',
'};',
'',
'console.log(obj[-0], obj[-""], obj["-0"]);',
'',
'console.log(obj[42], obj["42"]);',
'',
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
'',
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
]
expect_stdout: [
"0 0 1",
"3 3",
"4 5 4 4",
"8 7 8",
]
}

View File

@@ -0,0 +1,181 @@
return_1: {
beautify = {
beautify: false,
preserve_line: true,
}
input: {
console.log(function f() {
return (
f.toString() != 42
);
}());
}
expect_exact: [
"console.log(function f(){",
"",
"return 42!=f.toString()}());",
]
expect_stdout: "true"
}
return_2: {
beautify = {
beautify: true,
preserve_line: true,
}
input: {
console.log(function f() {
return (
f.toString() != 42
);
}());
}
expect_exact: [
"console.log(function f() {",
"",
" return 42 != f.toString();",
"}());",
]
expect_stdout: "true"
}
return_3: {
options = {}
beautify = {
beautify: false,
preserve_line: true,
}
input: {
console.log(function f() {
return (
f.toString() != 42
);
}());
}
expect_exact: [
"console.log(function f(){",
"",
"return 42!=f.toString()}());",
]
expect_stdout: "true"
}
return_4: {
options = {}
beautify = {
beautify: true,
preserve_line: true,
}
input: {
console.log(function f() {
return (
f.toString() != 42
);
}());
}
expect_exact: [
"console.log(function f() {",
"",
" return 42 != f.toString();",
"}());",
]
expect_stdout: "true"
}
return_5: {
beautify = {
beautify: false,
preserve_line: true,
}
input: {
_is_selected = function(tags, slug) {
var ref;
return (ref = _.find(tags, {
slug: slug
})) != null ? ref.selected : void 0;
};
}
expect_exact: [
"_is_selected=function(tags,slug){",
"var ref",
"",
"",
";return null!=(ref=_.find(tags,{slug:slug}))?ref.selected:void 0};",
]
}
return_6: {
beautify = {
beautify: true,
preserve_line: true,
}
input: {
_is_selected = function(tags, slug) {
var ref;
return (ref = _.find(tags, {
slug: slug
})) != null ? ref.selected : void 0;
};
}
expect_exact: [
"_is_selected = function(tags, slug) {",
" var ref;",
"",
"",
" return null != (ref = _.find(tags, {",
" slug: slug",
" })) ? ref.selected : void 0;",
"};",
]
}
return_7: {
options = {}
mangle = {}
beautify = {
beautify: false,
preserve_line: true,
}
input: {
_is_selected = function(tags, slug) {
var ref;
return (ref = _.find(tags, {
slug: slug
})) != null ? ref.selected : void 0;
};
}
expect_exact: [
"_is_selected=function(e,l){",
"var n",
"",
"",
";return null!=(n=_.find(e,{slug:l}))?n.selected:void 0};",
]
}
return_8: {
options = {}
mangle = {}
beautify = {
beautify: true,
preserve_line: true,
}
input: {
_is_selected = function(tags, slug) {
var ref;
return (ref = _.find(tags, {
slug: slug
})) != null ? ref.selected : void 0;
};
}
expect_exact: [
"_is_selected = function(e, l) {",
" var n;",
"",
"",
" return null != (n = _.find(e, {",
" slug: l",
" })) ? n.selected : void 0;",
"};",
]
}

View File

@@ -817,6 +817,29 @@ issue_2208_5: {
expect_stdout: "42" expect_stdout: "42"
} }
issue_2208_6: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
a = 42;
console.log(("FAIL", {
p: function() {
return this.a;
}
}.p)());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
}
issue_2256: { issue_2256: {
options = { options = {
side_effects: true, side_effects: true,
@@ -1208,6 +1231,37 @@ join_object_assignments_3: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
join_object_assignments_4: {
options = {
join_vars: true,
sequences: true,
}
input: {
var o;
console.log(o);
o = {};
o.a = "foo";
console.log(o.b);
o.b = "bar";
console.log(o.a);
}
expect: {
var o;
console.log(o),
o = {
a: "foo",
},
console.log(o.b),
o.b = "bar",
console.log(o.a);
}
expect_stdout: [
"undefined",
"undefined",
"foo",
]
}
join_object_assignments_return_1: { join_object_assignments_return_1: {
options = { options = {
join_vars: true, join_vars: true,
@@ -1698,3 +1752,162 @@ issue_869_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3188_1: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
}
input: {
(function() {
function f() {
console.log(this.p);
}
(function() {
var o = {
p: "PASS",
f: f
};
o.f();
})();
})();
}
expect: {
(function() {
function f() {
console.log(this.p);
}
({
p: "PASS",
f: f
}).f();
var o;
})();
}
expect_stdout: "PASS"
}
issue_3188_2: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var f = function() {
console.log(this.p);
};
function g() {
var o = {
p: "PASS",
f: f
};
o.f();
}
g();
})();
}
expect: {
({
p: "PASS",
f: function() {
console.log(this.p);
}
}).f();
}
expect_stdout: "PASS"
}
issue_3188_3: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
}
input: {
(function() {
function f() {
console.log(this[0]);
}
(function() {
var o = ["PASS", f];
o[1]();
})();
})();
}
expect: {
(function() {
function f() {
console.log(this[0]);
}
["PASS", f][1]();
var o;
})();
}
expect_stdout: "PASS"
}
join_expr: {
options = {
evaluate: true,
join_vars: true,
}
input: {
var c = "FAIL";
(function() {
var a = 0;
switch ((a = {}) && (a.b = 0)) {
case 0:
c = "PASS";
}
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function() {
var a = 0;
switch (a = { b: 0 }, a.b) {
case 0:
c = "PASS";
}
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3389: {
options = {
evaluate: true,
properties: true,
reduce_vars: true,
unsafe: true,
}
input: {
(function() {
var a = "PASS";
if (delete b)
b = a[null] = 42;
console.log(a);
})();
}
expect: {
(function() {
var a = "PASS";
if (delete b)
b = a.null = 42;
console.log(a);
})();
}
expect_stdout: "PASS"
}

View File

@@ -535,3 +535,148 @@ issue_2705_6: {
"/* */new(/* */a()||b())(c(),d());", "/* */new(/* */a()||b())(c(),d());",
] ]
} }
issue_3065_1: {
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_2: {
rename = true
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
mangle = {
reserved: [ "pureFunc" ],
toplevel: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_3: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function debug(msg) {
console.log(msg);
}
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}
issue_3065_4: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var debug = function(msg) {
console.log(msg);
};
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}
issue_3325_1: {
options = {
pure_funcs: "cb",
side_effects: true,
}
input: {
function cb() {
console.log("PASS");
}
cb();
}
expect: {
function cb() {
console.log("PASS");
}
}
}
issue_3325_2: {
options = {
pure_funcs: "xxxcbxxx",
side_effects: true,
}
input: {
function cb() {
console.log("PASS");
}
cb();
}
expect: {
function cb() {
console.log("PASS");
}
cb();
}
expect_stdout: "PASS"
}

View File

@@ -187,10 +187,10 @@ issue_2110_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
pure_getters: "strict", pure_getters: "strict",
sequences: true,
side_effects: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true,
side_effects: true,
unused: true, unused: true,
} }
input: { input: {
@@ -1161,3 +1161,51 @@ collapse_rhs_lhs: {
} }
expect_stdout: "1 3" expect_stdout: "1 3"
} }
drop_arguments: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
(function() {
arguments.slice = function() {
console.log("PASS");
};
arguments[42];
arguments.length;
arguments.slice();
})();
}
expect: {
(function() {
arguments.slice = function() {
console.log("PASS");
};
arguments.slice();
})();
}
expect_stdout: "PASS"
}
issue_3427: {
options = {
assignments: true,
collapse_vars: true,
inline: true,
passes: 2,
pure_getters: "strict",
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
(function(b) {
b.p = 42;
})(a || (a = {}));
}
expect: {}
expect_stdout: true
}

File diff suppressed because it is too large Load Diff

475
test/compress/regexp.js Normal file
View File

@@ -0,0 +1,475 @@
regexp_simple: {
input: {
/rx/ig
}
expect_exact: "/rx/gi;"
}
regexp_slashes: {
input: {
/\\\/rx\/\\/ig
}
expect_exact: "/\\\\\\/rx\\/\\\\/gi;"
}
regexp_1: {
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/ig)));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}
regexp_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(new RegExp("([Sap]+)", "ig"))));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}
regexp_properties: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(/abc/g.source, /abc/g.global, /abc/g.ignoreCase, /abc/g.lastIndex, /abc/g.multiline);
}
expect: {
console.log("abc", true, false, /abc/g.lastIndex, false);
}
expect_stdout: "abc true false 0 false"
}
issue_3434_1: {
options = {
evaluate: true,
unsafe: true,
}
beautify = {
beautify: true,
}
input: {
var o = {
"\n": RegExp("\n"),
"\r": RegExp("\r"),
"\t": RegExp("\t"),
"\b": RegExp("\b"),
"\f": RegExp("\f"),
"\0": RegExp("\0"),
"\x0B": RegExp("\x0B"),
"\u2028": RegExp("\u2028"),
"\u2029": RegExp("\u2029"),
};
for (var c in o)
console.log(o[c].test("\\"), o[c].test(c));
}
expect_exact: [
"var o = {",
' "\\n": /\\n/,',
' "\\r": /\\r/,',
' "\\t": /\t/,',
' "\\b": /\b/,',
' "\\f": /\f/,',
' "\\0": /\0/,',
' "\\v": /\v/,',
' "\\u2028": /\\u2028/,',
' "\\u2029": /\\u2029/',
"};",
"",
'for (var c in o) console.log(o[c].test("\\\\"), o[c].test(c));',
]
expect_stdout: [
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
]
}
issue_3434_2: {
options = {
evaluate: true,
unsafe: true,
}
beautify = {
beautify: true,
}
input: {
var o = {
"\n": RegExp("\\\n"),
"\r": RegExp("\\\r"),
"\t": RegExp("\\\t"),
"\b": RegExp("\\\b"),
"\f": RegExp("\\\f"),
"\0": RegExp("\\\0"),
"\x0B": RegExp("\\\x0B"),
"\u2028": RegExp("\\\u2028"),
"\u2029": RegExp("\\\u2029"),
};
for (var c in o)
console.log(o[c].test("\\"), o[c].test(c));
}
expect_exact: [
"var o = {",
' "\\n": /\\n/,',
' "\\r": /\\r/,',
' "\\t": /\t/,',
' "\\b": /\b/,',
' "\\f": /\f/,',
' "\\0": /\0/,',
' "\\v": /\v/,',
' "\\u2028": /\\u2028/,',
' "\\u2029": /\\u2029/',
"};",
"",
'for (var c in o) console.log(o[c].test("\\\\"), o[c].test(c));',
]
expect_stdout: [
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
]
}
issue_3434_3: {
options = {
evaluate: true,
unsafe: true,
}
input: {
RegExp("\n");
RegExp("\r");
RegExp("\\n");
RegExp("\\\n");
RegExp("\\\\n");
RegExp("\\\\\n");
RegExp("\\\\\\n");
RegExp("\\\\\\\n");
RegExp("\u2028");
RegExp("\u2029");
RegExp("\n\r\u2028\u2029");
RegExp("\\\nfo\n[\n]o\\bbb");
}
expect: {
/\n/;
/\r/;
/\n/;
/\n/;
/\\n/;
/\\\n/;
/\\\n/;
/\\\n/;
/\u2028/;
/\u2029/;
/\n\r\u2028\u2029/;
/\nfo\n[\n]o\bbb/;
}
}
issue_3434_4: {
options = {
evaluate: true,
unsafe: true,
}
input: {
[
[ "", RegExp("") ],
[ "/", RegExp("/") ],
[ "//", RegExp("//") ],
[ "\/", RegExp("\\/") ],
[ "///", RegExp("///") ],
[ "/\/", RegExp("/\\/") ],
[ "\//", RegExp("\\//") ],
[ "\\/", RegExp("\\\\/") ],
[ "////", RegExp("////") ],
[ "//\/", RegExp("//\\/") ],
[ "/\//", RegExp("/\\//") ],
[ "/\\/", RegExp("/\\\\/") ],
[ "\///", RegExp("\\///") ],
[ "\/\/", RegExp("\\/\\/") ],
[ "\\//", RegExp("\\\\//") ],
[ "\\\/", RegExp("\\\\\\/") ],
].forEach(function(test) {
console.log(test[1].test("\\"), test[1].test(test[0]));
});
}
expect: {
[
[ "", /(?:)/ ],
[ "/", /\// ],
[ "//", /\/\// ],
[ "/", /\// ],
[ "///", /\/\/\// ],
[ "//", /\/\// ],
[ "//", /\/\// ],
[ "\\/", /\\\// ],
[ "////", /\/\/\/\// ],
[ "///", /\/\/\// ],
[ "///", /\/\/\// ],
[ "/\\/", /\/\\\// ],
[ "///", /\/\/\// ],
[ "//", /\/\// ],
[ "\\//", /\\\/\// ],
[ "\\/", /\\\// ],
].forEach(function(test) {
console.log(test[1].test("\\"), test[1].test(test[0]));
});
}
expect_stdout: [
"true true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
]
}
exec: {
options = {
evaluate: true,
loops: true,
unsafe: true,
}
input: {
while (/a/.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
exec_global: {
options = {
evaluate: true,
loops: true,
unsafe: true,
}
input: {
while (/a/g.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
test: {
options = {
evaluate: true,
unsafe: true,
}
input: {
while (/a/.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
test_global: {
options = {
evaluate: true,
unsafe: true,
}
input: {
while (/a/g.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_exec: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/;
while (r.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
var r = /a/;
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_exec_global: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/g;
while (r.exec("aaa"))
console.log("PASS");
}
expect: {
var r = /a/g;
for (;r.exec("aaa");)
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
}
var_test: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/;
while (r.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
var r = /a/;
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_test_global: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/g;
while (r.test("aaa"))
console.log("PASS");
}
expect: {
var r = /a/g;
while (r.test("aaa"))
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
}
lazy_boolean: {
options = {
evaluate: true,
passes: 2,
side_effects: true,
unsafe: true,
}
input: {
/b/.exec({}) && console.log("PASS");
/b/.test({}) && console.log("PASS");
/b/g.exec({}) && console.log("PASS");
/b/g.test({}) && console.log("PASS");
}
expect: {
console.log("PASS");
console.log("PASS");
console.log("PASS");
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
]
}
reset_state_between_evaluate: {
options = {
evaluate: true,
passes: 2,
unsafe: true,
}
input: {
console.log(function() {
for (var a in /[abc4]/g.exec("a"))
return "PASS";
return "FAIL";
}());
}
expect: {
console.log(function() {
for (var a in /[abc4]/g.exec("a"))
return "PASS";
return "FAIL";
}());
}
expect_stdout: "PASS"
}

View File

@@ -534,3 +534,208 @@ function_catch_catch_ie8: {
"undefined", "undefined",
] ]
} }
function_do_catch_ie8: {
rename = true
options = {
ie8: true,
side_effects: true,
unused: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = 1, b = 1, c = 0;
function d(e) {
var f, g, h, i;
do {
try {
try {
var j = function q(){}();
} catch (r) {
--a && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
var k, l, m, n, o;
--m;
--n;
--o;
}
try {
i[1];
} catch (s) {
var p;
switch (function t() {
c++;
}()) {
case j + --p:
}
}
} catch (u) {}
} while (--i);
b--;
}
d();
console.log(b, c);
}
expect: {
var u = 1, y = 1, a = 0;
function c(c) {
var d;
do {
try {
try {
var e = void 0;
} catch (i) {
--u && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
0;
0;
0;
}
try {
d[1];
} catch (l) {
var g;
switch (function n() {
a++;
}()) {
case e + --g:
}
}
} catch (t) {}
} while (--d);
y--;
}
c();
console.log(y, a);
}
expect_stdout: "0 1"
}
issue_3480: {
rename = true,
mangle = {
ie8: false,
toplevel: false,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var d, a, b, c = "FAIL";
(function n() {
(function() {
try {
c = "PASS";
} catch (c) {}
})();
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3480_ie8: {
rename = true,
mangle = {
ie8: true,
toplevel: false,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {}
})();
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3480_toplevel: {
rename = true,
mangle = {
ie8: false,
toplevel: true,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var c, n, o, t = "FAIL";
(function c() {
(function() {
try {
t = "PASS";
} catch (c) {}
})();
})();
console.log(t);
}
expect_stdout: "PASS"
}
issue_3480_ie8_toplevel: {
rename = true,
mangle = {
ie8: true,
toplevel: true,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var c, n, o, t = "FAIL";
(function o() {
(function() {
try {
t = "PASS";
} catch (o) {}
})();
})();
console.log(t);
}
expect_stdout: "PASS"
}

View File

@@ -1,24 +1,24 @@
return_undefined: { return_undefined: {
options = { options = {
sequences : false, booleans: true,
if_return : true, comparisons: true,
evaluate : true, conditionals: true,
dead_code : true, dead_code: true,
conditionals : true, drop_debugger: true,
comparisons : true, evaluate: true,
booleans : true, hoist_funs: true,
unused : true, hoist_vars: true,
side_effects : true, if_return: true,
properties : true, join_vars: true,
drop_debugger : true, keep_fargs: true,
loops : true, keep_fnames: false,
hoist_funs : true, loops: true,
keep_fargs : true, negate_iife: true,
keep_fnames : false, properties: true,
hoist_vars : true, sequences: false,
join_vars : true, side_effects: true,
negate_iife : true unused: true,
}; }
input: { input: {
function f0() { function f0() {
} }

View File

@@ -12,3 +12,71 @@ console_log: {
"% %s", "% %s",
] ]
} }
typeof_arguments: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var arguments;
console.log((typeof arguments).length);
}
expect: {
var arguments;
console.log((typeof arguments).length);
}
expect_stdout: "6"
}
typeof_arguments_assigned: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var arguments = void 0;
console.log((typeof arguments).length);
}
expect: {
console.log("undefined".length);
}
expect_stdout: "9"
}
toplevel_Infinity_NaN_undefined: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var Infinity = "foo";
var NaN = 42;
var undefined = null;
console.log(Infinity, NaN, undefined);
}
expect: {
console.log("foo", 42, null);
}
expect_stdout: "foo 42 null"
}
log_global: {
input: {
console.log(function() {
return this;
}());
}
expect: {
console.log(function() {
return this;
}());
}
expect_stdout: "[object global]"
}

View File

@@ -1,7 +1,7 @@
make_sequences_1: { make_sequences_1: {
options = { options = {
sequences: true sequences: true,
}; }
input: { input: {
foo(); foo();
bar(); bar();
@@ -14,8 +14,8 @@ make_sequences_1: {
make_sequences_2: { make_sequences_2: {
options = { options = {
sequences: true sequences: true,
}; }
input: { input: {
if (boo) { if (boo) {
foo(); foo();
@@ -35,8 +35,8 @@ make_sequences_2: {
make_sequences_3: { make_sequences_3: {
options = { options = {
sequences: true sequences: true,
}; }
input: { input: {
function f() { function f() {
foo(); foo();
@@ -61,8 +61,8 @@ make_sequences_3: {
make_sequences_4: { make_sequences_4: {
options = { options = {
sequences: true sequences: true,
}; }
input: { input: {
x = 5; x = 5;
if (y) z(); if (y) z();
@@ -90,7 +90,9 @@ make_sequences_4: {
} }
lift_sequences_1: { lift_sequences_1: {
options = { sequences: true }; options = {
sequences: true,
}
input: { input: {
var foo, x, y, bar; var foo, x, y, bar;
foo = !(x(), y(), bar()); foo = !(x(), y(), bar());
@@ -102,7 +104,10 @@ lift_sequences_1: {
} }
lift_sequences_2: { lift_sequences_2: {
options = { sequences: true, evaluate: true }; options = {
evaluate: true,
sequences: true,
}
input: { input: {
var foo = 1, bar; var foo = 1, bar;
foo.x = (foo = {}, 10); foo.x = (foo = {}, 10);
@@ -119,7 +124,10 @@ lift_sequences_2: {
} }
lift_sequences_3: { lift_sequences_3: {
options = { sequences: true, conditionals: true }; options = {
conditionals: true,
sequences: true,
}
input: { input: {
var x, foo, bar, baz; var x, foo, bar, baz;
x = (foo(), bar(), baz()) ? 10 : 20; x = (foo(), bar(), baz()) ? 10 : 20;
@@ -131,7 +139,9 @@ lift_sequences_3: {
} }
lift_sequences_4: { lift_sequences_4: {
options = { side_effects: true }; options = {
side_effects: true,
}
input: { input: {
var x, foo, bar, baz; var x, foo, bar, baz;
x = (foo, bar, baz); x = (foo, bar, baz);
@@ -160,7 +170,9 @@ lift_sequences_5: {
} }
for_sequences: { for_sequences: {
options = { sequences: true }; options = {
sequences: true,
}
input: { input: {
// 1 // 1
foo(); foo();
@@ -203,7 +215,7 @@ for_sequences: {
limit_1: { limit_1: {
options = { options = {
sequences: 3, sequences: 3,
}; }
input: { input: {
a; a;
b; b;
@@ -228,7 +240,7 @@ limit_1: {
limit_2: { limit_2: {
options = { options = {
sequences: 3, sequences: 3,
}; }
input: { input: {
a, b; a, b;
c, d; c, d;
@@ -246,9 +258,9 @@ limit_2: {
negate_iife_for: { negate_iife_for: {
options = { options = {
sequences: true,
negate_iife: true, negate_iife: true,
}; sequences: true,
}
input: { input: {
(function() {})(); (function() {})();
for (i = 0; i < 5; i++) console.log(i); for (i = 0; i < 5; i++) console.log(i);
@@ -265,7 +277,7 @@ negate_iife_for: {
iife: { iife: {
options = { options = {
sequences: true, sequences: true,
}; }
input: { input: {
x = 42; x = 42;
(function a() {})(); (function a() {})();
@@ -478,6 +490,7 @@ issue_1758: {
delete_seq_1: { delete_seq_1: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -502,6 +515,7 @@ delete_seq_1: {
delete_seq_2: { delete_seq_2: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -526,6 +540,7 @@ delete_seq_2: {
delete_seq_3: { delete_seq_3: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
side_effects: true, side_effects: true,
} }
@@ -551,6 +566,7 @@ delete_seq_3: {
delete_seq_4: { delete_seq_4: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
} }
@@ -578,6 +594,7 @@ delete_seq_4: {
delete_seq_5: { delete_seq_5: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -606,6 +623,7 @@ delete_seq_5: {
delete_seq_6: { delete_seq_6: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -690,7 +708,7 @@ side_effects_cascade_3: {
} }
expect: { expect: {
function f(a, b) { function f(a, b) {
!(b += a) && ((b = a) || (b -= a, b ^= a)), (b += a) || (b = a) || (b -= a, b ^= a),
a--; a--;
} }
} }
@@ -876,3 +894,221 @@ forin: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
call: {
options = {
sequences: true,
}
input: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
};
(a, b)();
(a, b).c();
(a, b.c)();
(a, b)["c"]();
(a, b["c"])();
(a, function() {
console.log(this === a);
})();
new (a, b)();
new (a, b).c();
new (a, b.c)();
new (a, b)["c"]();
new (a, b["c"])();
new (a, function() {
console.log(this === a);
})();
console.log(typeof (a, b).c);
console.log(typeof (a, b)["c"]);
}
expect: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
},
b(),
b.c(),
(a, b.c)(),
b["c"](),
(a, b["c"])(),
function() {
console.log(this === a);
}(),
new b(),
new b.c(),
new b.c(),
new b["c"](),
new b["c"](),
new function() {
console.log(this === a);
}(),
console.log((a, typeof b.c)),
console.log((a, typeof b["c"]));
}
expect_stdout: [
"foo",
"bar",
"baz",
"bar",
"baz",
"true",
"foo",
"baz",
"baz",
"baz",
"baz",
"false",
"function",
"function",
]
}
missing_link: {
options = {
conditionals: true,
evaluate: true,
sequences: true,
}
input: {
var a = 100;
a;
a++ + (0 ? 2 : 1);
console.log(a);
}
expect: {
var a = 100;
a,
a++,
console.log(a);
}
}
angularjs_chain: {
options = {
conditionals: true,
sequences: true,
side_effects: true,
}
input: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
if (create && create !== 1) {
if (lhs && lhs[right] == null) {
lhs[right] = {};
}
}
var value = lhs != null ? lhs[right] : undefined;
if (context) {
return { context: lhs, name: right, value: value };
} else {
return value;
}
}
}
expect: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
var value = null != lhs ? lhs[right] : void 0;
return context ? {
context: lhs,
name: right,
value: value
} : value;
}
}
}
issue_3490_1: {
options = {
conditionals: true,
dead_code: true,
inline: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var b = 42, c = "FAIL";
if ({
3: function() {
var a;
return (a && a.p) < this;
}(),
}) c = "PASS";
if (b) while ("" == typeof d);
console.log(c, b);
}
expect: {
var b = 42, c = "FAIL";
if (function() {
var a;
a && a.p;
}(), c = "PASS", b) while ("" == typeof d);
console.log(c, b);
}
expect_stdout: "PASS 42"
}
issue_3490_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
inline: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var b = 42, c = "FAIL";
if ({
3: function() {
var a;
return (a && a.p) < this;
}(),
}) c = "PASS";
if (b) for (; "" == typeof d;);
console.log(c, b);
}
expect: {
var b = 42, c = "FAIL";
for (function() {
var a;
}(), c = "PASS", b; "" == typeof d;);
console.log(c, b);
}
expect_stdout: "PASS 42"
}
issue_3703: {
options = {
evaluate: true,
sequences: true,
unsafe: true,
}
input: {
var a = "FAIL";
while ((a = "PASS", 0).foo = 0);
console.log(a);
}
expect: {
var a = "FAIL";
while (a = "PASS", (0).foo = 0);
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -0,0 +1,277 @@
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}
unsafe_builtin_1: {
options = {
side_effects: true,
unsafe: true,
}
input: {
(!w).constructor(x);
Math.abs(y);
[ 1, 2, z ].valueOf();
}
expect: {
w, x;
y;
z;
}
}
unsafe_builtin_2: {
options = {
side_effects: true,
unsafe: true,
}
input: {
var o = {};
constructor.call(o, 42);
__defineGetter__.call(o, "foo", function() {
return o.p;
});
__defineSetter__.call(o, void 0, function(a) {
o.p = a;
});
console.log(typeof o, o.undefined = "PASS", o.foo);
}
expect: {
var o = {};
constructor.call(o, 42);
__defineGetter__.call(o, "foo", function() {
return o.p;
});
__defineSetter__.call(o, void 0, function(a) {
o.p = a;
});
console.log(typeof o, o.undefined = "PASS", o.foo);
}
expect_stdout: "object PASS PASS"
}
unsafe_string_replace: {
options = {
side_effects: true,
unsafe: true,
}
input: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
drop_value: {
options = {
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), bar();
}
}

View File

@@ -14,6 +14,13 @@ issue_1929: {
function f(s) { function f(s) {
return s.split(/[\\/]/); return s.split(/[\\/]/);
} }
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
} }
expect_exact: "function f(s){return s.split(/[\\\\/]/)}" expect: {
function f(s) {
return s.split(/[\\/]/);
}
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
}
expect_stdout: '["A","B","C","D","E","F"]'
} }

View File

@@ -261,13 +261,13 @@ drop_default_1: {
} }
input: { input: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
default: default:
} }
} }
expect: { expect: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
} }
} }
} }
@@ -279,14 +279,14 @@ drop_default_2: {
} }
input: { input: {
switch (foo) { switch (foo) {
case 'bar': baz(); break; case "bar": baz(); break;
default: default:
break; break;
} }
} }
expect: { expect: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
} }
} }
} }
@@ -298,7 +298,7 @@ keep_default: {
} }
input: { input: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
default: default:
something(); something();
break; break;
@@ -306,7 +306,7 @@ keep_default: {
} }
expect: { expect: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
default: default:
something(); something();
} }
@@ -347,25 +347,103 @@ issue_1663: {
expect_stdout: true expect_stdout: true
} }
drop_case: { drop_case_1: {
options = { options = {
dead_code: true, dead_code: true,
switches: true, switches: true,
} }
input: { input: {
switch (foo) { switch (foo) {
case 'bar': baz(); break; case "bar": baz(); break;
case 'moo': case "moo":
break; break;
} }
} }
expect: { expect: {
switch (foo) { switch (foo) {
case 'bar': baz(); case "bar": baz();
} }
} }
} }
drop_case_2: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case "bar":
bar();
break;
default:
case "moo":
moo();
break;
}
}
expect: {
switch (foo) {
case "bar":
bar();
break;
default:
moo();
}
}
}
drop_case_3: {
options = {
dead_code: true,
switches: true,
}
input: {
var c = "PASS";
switch ({}.p) {
default:
case void 0:
break;
case c = "FAIL":
}
console.log(c);
}
expect: {
var c = "PASS";
switch ({}.p) {
default:
case void 0:
break;
case c = "FAIL":
}
console.log(c);
}
expect_stdout: "PASS"
}
drop_case_4: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (0) {
case [ a, typeof b ]:
default:
var a;
}
console.log("PASS");
}
expect: {
switch (0) {
case [ a, typeof b ]:
var a;
}
console.log("PASS");
}
expect_stdout: "PASS"
}
keep_case: { keep_case: {
options = { options = {
dead_code: true, dead_code: true,
@@ -373,14 +451,14 @@ keep_case: {
} }
input: { input: {
switch (foo) { switch (foo) {
case 'bar': baz(); break; case "bar": baz(); break;
case moo: case moo:
break; break;
} }
} }
expect: { expect: {
switch (foo) { switch (foo) {
case 'bar': baz(); break; case "bar": baz(); break;
case moo: case moo:
} }
} }
@@ -539,7 +617,7 @@ issue_1679: {
f(); f();
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "99 8"
} }
issue_1680_1: { issue_1680_1: {
@@ -820,8 +898,8 @@ issue_1758: {
issue_2535: { issue_2535: {
options = { options = {
evaluate: true,
dead_code: true, dead_code: true,
evaluate: true,
switches: true, switches: true,
} }
input: { input: {
@@ -864,3 +942,89 @@ issue_1750: {
} }
expect_stdout: "0 2" expect_stdout: "0 2"
} }
drop_switch_1: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
default:
break;
case "bar":
break;
}
}
expect: {
foo;
}
}
drop_switch_2: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
default:
case "bar":
baz();
}
}
expect: {
foo;
baz();
}
}
drop_switch_3: {
options = {
dead_code: true,
switches: true,
}
input: {
console.log(function() {
switch (0) {
default:
return "PASS";
case 1:
}
}());
}
expect: {
console.log(function() {
switch (0) {
default:
return "PASS";
case 1:
}
}());
}
expect_stdout: "PASS"
}
drop_switch_4: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = "FAIL";
switch (0) {
default:
case a:
var b = a = "PASS";
break;
}
console.log(a);
}
expect: {
var a = "FAIL";
0;
var b = a = "PASS";
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -103,6 +103,7 @@ if_return: {
booleans: true, booleans: true,
conditionals: true, conditionals: true,
if_return: true, if_return: true,
passes: 2,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
} }

Some files were not shown because too many files have changed in this diff Show More