Compare commits

...

782 Commits

Author SHA1 Message Date
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
Alex Lam S.L
87857b0f1b v3.3.20 2018-04-08 03:06:15 +08:00
Alex Lam S.L
e5f6a88233 fix corner case in reuse of mangle options (#3062) 2018-04-08 02:29:37 +08:00
Alex Lam S.L
8d0b00317e v3.3.19 2018-04-07 22:27:55 +08:00
Alex Lam S.L
db49daf365 mangle Object.defineProperty() (#3059)
fixes #869
2018-04-06 17:10:36 +08:00
Alex Lam S.L
923deeff35 support inline source map from multiple files (#3058)
fixes #145
2018-04-06 16:04:15 +08:00
Alex Lam S.L
0b62a28b47 improve usability of includeSources (#3057)
Exclude source contents from input source map if `includeSources=false`

fixes #3041
2018-04-06 13:32:26 +08:00
Alex Lam S.L
44116c6d2b fix AST corruption during inline of simple return (#3056)
fixes #3054
2018-04-06 05:39:07 +08:00
Alex Lam S.L
b5bab254ce speed up has_parens() (take 2) (#3052)
fixes #3050
2018-04-05 04:12:04 +08:00
Alex Lam S.L
81603ecd15 improve performance through makePredicate() (#3048) 2018-04-03 15:15:01 +08:00
Alex Lam S.L
e67553fa55 fix tree traversal on AST_Do (#3047)
fixes #3046
2018-04-02 22:31:23 +08:00
Alex Lam S.L
fcf542f262 v3.3.18 2018-04-02 04:26:28 +00:00
b-fuze
8adfc29f91 Don't load source map until the JS source is fully received (#3040) 2018-03-31 20:26:40 +09:00
Alex Lam S.L
02f47e1713 give sensible error against invalid input source map (#3044) 2018-03-31 18:48:20 +09:00
Alex Lam S.L
07f64d4050 fix escape analysis on AST_New (#3043)
fixes #3042
2018-03-31 15:03:46 +09:00
Alex Lam S.L
6982a0554c v3.3.17 2018-03-31 04:13:45 +00:00
Alex Lam S.L
fa3250199a mangle unused nested AST_SymbolCatch correctly (#3038)
fixes #3035
2018-03-30 16:23:09 +09:00
Alex Lam S.L
06b9894c19 handle modifications to this correctly (#3036)
fixes #3032
2018-03-30 15:07:36 +09:00
Alex Lam S.L
9f9db504d7 improve test for #3023 (#3031) 2018-03-29 23:36:40 +09:00
Alex Lam S.L
82ae95c334 improve source map granularity (#3030)
fixes #3023
2018-03-29 14:47:55 +09:00
Fábio Santos
9a5e2052c4 fix extra regex slash when going through mozilla AST I/O (#3025)
This relates to #1929, but in the context of mozilla AST input/output.
2018-03-27 03:22:01 +09:00
Alex Lam S.L
b1410be443 speed up has_parens() (#3014) 2018-03-24 04:05:28 +08:00
Alex Lam S.L
12985d86c2 fix corner case in hoist_props (#3022)
fixes #3021
2018-03-23 07:27:35 +08:00
Alex Lam S.L
49bfc6b555 improve performance (#3020)
- replace `find_if()` with `all()` wherever possible
- move ESTree-specific logic out of `figure_out_scope()`
2018-03-23 03:43:52 +08:00
Alex Lam S.L
d1c6bb8c7c fix nested inline within loop (#3019)
fixes #3018
2018-03-23 02:31:59 +08:00
Alex Lam S.L
5c169615a8 fix corner case in inline (#3017)
fixes #3016
2018-03-22 23:46:26 +08:00
Alex Lam S.L
73d77f4f64 v3.3.16 2018-03-19 06:53:51 +00:00
Alex Lam S.L
ccf0e2ef4f extend fuzzy RHS folding (#3006)
- `a = []; if (1) x();` => `if (a = []) x();`
2018-03-17 03:10:21 +08:00
Alex Lam S.L
20ca0f5906 improve truthy compression (#3009) 2018-03-16 06:12:59 +08:00
Alex Lam S.L
b29d435bb5 refactor brackets to braces (#3005) 2018-03-15 15:46:45 +08:00
Alex Lam S.L
90585e29c2 v3.3.15 2018-03-14 16:45:38 +00:00
Alex Lam S.L
d8fc281915 update dependencies (#3002)
acorn 5.5.3
commander 2.15.0

Miscellaneous
- drop unmaintained package from README
2018-03-14 15:54:41 +08:00
Alex Lam S.L
188c39e8d5 retain comments within brackets (#2999)
fixes #2998
2018-03-13 18:44:21 +08:00
Alex Lam S.L
5429234138 preserve non-constant value assignments with modifications (#2997)
fixes #2995
2018-03-13 17:35:34 +08:00
Alex Lam S.L
b9f72a4a81 handle case correctly under reduce_vars (#2993)
fixes #2992
2018-03-11 15:54:43 +08:00
Alex Lam S.L
fc6ebd04a5 preserve case when inline_script (#2991)
fixes #2989
2018-03-11 05:11:12 +08:00
Alex Lam S.L
7e00a12741 v3.3.14 2018-03-10 13:20:14 +00:00
Alex Lam S.L
10b3752b1e fix mangle of AST_SymbolLambda under ie8 (#2978)
fixes #2976
2018-03-07 17:20:38 +08:00
Alex Lam S.L
fe51a91395 handle negated constants correctly in collapse_vars (#2975)
fixes #2974
2018-03-06 00:45:58 +08:00
Alex Lam S.L
951d87ca94 v3.3.13 2018-03-04 07:38:49 +00:00
Alex Lam S.L
798fc21530 improve test/run-test.js performance (#2971)
- allow reuse of contextified sandbox
- minimise bottleneck from `vm.createContext()`
2018-03-04 04:50:00 +08:00
Alex Lam S.L
a75a046abb compress arguments[index] (#2967)
- always replace with existing parameter
- only introduce new parameter if `keep_fargs` is disabled
2018-03-02 11:22:09 +08:00
Alex Lam S.L
38f2b4579f fix value reference caching in evaluate (#2969)
fixes #2968
2018-03-02 04:04:29 +08:00
Alex Lam S.L
56e2a369d0 enhance conditionals (#2966)
- `x ? (y, w) : (z, w)` => `x ? y : z, w`
2018-02-28 23:34:48 +08:00
Alex Lam S.L
0daa199fa8 migrate safe transformations out of unsafe_comps (#2962)
fixes #2959
2018-02-28 22:02:24 +08:00
Alex Lam S.L
73e98dcda4 drop side_effects-free return values (#2965) 2018-02-28 19:59:19 +08:00
Alex Lam S.L
36bca6934d enhance collapse_vars (#2952)
- `a = b, b` => `a = b`
- `a.b = c, c()` => `(a.b = c)()`
2018-02-28 15:19:32 +08:00
Alex Lam S.L
ace5811691 drop lone "use strict" in function body (#2963)
fixes #2961
2018-02-26 15:22:52 +08:00
Dan
ba7bad0dbd show benchmark subtotal (#2960)
At the end of the benchmark, sums of the input, output and
gzip values are shown, such as:

    Subtotal

    Original: 7785102 bytes
    Uglified: 2283862 bytes
    GZipped:  662354 bytes
2018-02-26 11:46:26 +08:00
Alex Lam S.L
b8b2ac5230 improve fix for #2954 (#2958) 2018-02-26 03:14:22 +08:00
Alex Lam S.L
ea2359381b fix collapse_vars on nested exception (#2955)
fixes #2954
2018-02-25 15:39:00 +08:00
Alex Lam S.L
52de64cf16 deduplicate parenthesis around object and function literals (#2953) 2018-02-25 02:14:33 +08:00
Alex Lam S.L
455790202a minor clean-ups (#2951) 2018-02-24 02:24:47 +08:00
Alex Lam S.L
f40f5eb228 improve mangle (#2948) 2018-02-23 23:51:49 +08:00
Alex Lam S.L
604caa09e7 v3.3.12 2018-02-22 08:14:29 +00:00
Alex Lam S.L
29a71d3aae more tests for #2938 (#2940) 2018-02-21 04:19:42 +08:00
Alex Lam S.L
39a907bde3 workaround pure_getters=true when dropping unused assignments (#2939)
fixes #2938
2018-02-20 17:38:40 +08:00
Alex Lam S.L
70474310f3 improve unsafe evaluate of function (#2936)
Miscellaneous
- simplify `run_code()` hack
2018-02-19 18:47:02 +08:00
Alex Lam S.L
b5f0f4f3a1 reduce false positives from object literals (#2935) 2018-02-19 06:21:07 +08:00
Alex Lam S.L
2905fd625a reduce false positives from labels (#2934) 2018-02-19 03:55:33 +08:00
Alex Lam S.L
4facd94029 reduce false positives from noop (#2933) 2018-02-19 01:15:05 +08:00
Alex Lam S.L
4b5993ff15 fix crash in may_throw() (#2932)
fixes #2931
2018-02-18 21:51:27 +08:00
Alex Lam S.L
2351a672ea fix dead_code on exceptional return (#2930)
fixes #2929
2018-02-18 04:36:00 +08:00
Alex Lam S.L
4a528c469c reduce false positives from function.toString() (#2928) 2018-02-18 02:13:26 +08:00
Alex Lam S.L
82d1ef0242 fix unsafe evaluate of function property (#2927)
fixes #2926
2018-02-17 21:33:36 +08:00
Alex Lam S.L
7fdd2082a6 drop unused "class" definition IIFEs (#2923)
fixes #805
2018-02-17 05:11:31 +08:00
Alex Lam S.L
e529f54e90 reduce function-related false positives (#2925) 2018-02-17 04:35:03 +08:00
Alex Lam S.L
d626e9bf19 improve inline efficiency (#2924) 2018-02-17 02:37:13 +08:00
Alex Lam S.L
a2a9459684 fix unsafe evaluate of AST_Function (#2920)
fixes #2919
2018-02-16 17:21:46 +08:00
Alex Lam S.L
a3dfeea144 v3.3.11 2018-02-15 19:24:35 +00:00
Alex Lam S.L
d316fb139d fix unsafe evaluate on type-converting operators (#2917)
fixes #2916
2018-02-14 16:48:47 +08:00
Alex Lam S.L
83d8aa8b12 fix collapse_vars within loops (#2915)
fixes #2914
2018-02-14 05:15:52 +08:00
Alex Lam S.L
4f1c12b6fd report options upon reminify input error (#2911) 2018-02-13 07:29:39 +08:00
Alex Lam S.L
d8e0e34354 collapse within unary expressions (#2910) 2018-02-13 07:10:37 +08:00
Alex Lam S.L
0c4f315c02 fix corner case in collapse_vars (#2909)
fixes #2908
2018-02-13 01:41:22 +08:00
Alex Lam S.L
0809699bdc simplify do-while into for (#2907)
fixes #2904
2018-02-12 23:28:28 +08:00
Alex Lam S.L
2088e1c19d fix AST corruption due to collapse_vars & inline (#2899)
fixes #2898
2018-02-09 06:54:37 +08:00
Alex Lam S.L
bf1d47180c fix join_vars on property accessors (#2895)
fixes #2893
2018-02-09 01:52:39 +08:00
Alex Lam S.L
0cfbd79aa1 v3.3.10 2018-02-08 10:16:16 +00:00
Alex Lam S.L
d66d86f20b account for exceptions in AST_Assign.left (#2892)
fixes #2891
2018-02-08 03:31:51 +08:00
Alex Lam S.L
905325d3e2 update dependencies (#2889)
acorn 5.4.1
commander 2.14.1
semver 5.5.0
2018-02-07 18:13:18 +08:00
Alex Lam S.L
dea0cc0662 mention file encoding (#2887) 2018-02-06 16:48:49 +08:00
Alex Lam S.L
d69d8007d6 evaluate to{Low,Upp}erCase() under unsafe (#2886) 2018-02-06 15:57:15 +08:00
Dan
c0b8f2a16d add information on testing and code style (#2885)
fixes #2884
2018-02-06 14:19:28 +08:00
Dan
cb0257dbbf describe a few compiler assumptions (#2883) 2018-02-06 14:19:03 +08:00
Dan
9637f51b68 change undefined == x to null == x (#2882)
fixes #2871
2018-02-05 15:00:23 +08:00
Alex Lam S.L
3026bd8975 improve exceptional flow compression by collapse_vars (#2880) 2018-02-04 04:18:22 +08:00
Alex Lam S.L
78a44d5ab0 maintain order between side-effects and externally observable assignments (#2879)
fixes #2878
2018-02-04 03:58:49 +08:00
Alex Lam S.L
7e13c0db40 handle break & continue in collapse_vars (#2875)
fixes #2873
2018-02-03 07:58:43 +08:00
Alex Lam S.L
e6a2e9e4d0 allow collapse_vars across conditional branches (#2867) 2018-02-03 02:44:40 +08:00
Alex Lam S.L
e773f03927 fix assignment logic in reduce_vars (#2872)
fixes #2869
2018-02-03 01:33:09 +08:00
Alex Lam S.L
b16380d669 fix missing corner case in #2855 (#2868) 2018-02-02 18:08:56 +08:00
Ryan Gunn
334b07a3db Update License Copyright Year to 2018 (#2866) 2018-02-02 16:30:01 +08:00
Alex Lam S.L
3cc1527f00 always test for rename (#2865) 2018-02-01 21:42:55 +08:00
Alex Lam S.L
525a61fb55 better fix for #2858 (#2864) 2018-02-01 20:06:36 +08:00
Alex Lam S.L
c3a002ff97 account for side-effects in comparisons of null & undefined (#2863) 2018-02-01 19:15:17 +08:00
Alex Lam S.L
fad6766a90 simplify comparisons with undefined & null (#2862)
fixes #2857
2018-02-01 16:50:54 +08:00
Alex Lam S.L
aa664dea0a avoid evaluate of compound assignment after dead_code transform (#2861)
fixes #2860
2018-02-01 16:18:29 +08:00
Alex Lam S.L
102f994b9d account for declaration assignment in collapse_vars (#2859)
fixes #2858
2018-02-01 15:09:53 +08:00
Alex Lam S.L
2a4c68be4f relax collapse_vars on AST_Exit (#2855)
First introduced in #1862 to stop assignments to migrate beyond `return` or `throw`. Since then `collapse_vars` has been improved to handle various side-effect-related corner cases.
2018-01-31 23:49:59 +08:00
Alex Lam S.L
541e6011af improve symbol replacement heuristic (#2851) 2018-01-29 17:41:15 +08:00
Alex Lam S.L
6fa3fbeae8 compress chained compound assignments (#2850) 2018-01-29 15:13:25 +08:00
Alex Lam S.L
4eb4cb656c v3.3.9 2018-01-27 12:56:34 +00:00
Alex Lam S.L
193612ac67 fix accounting after conversion to assignment (#2847)
Missing reference to `AST_SymbolRef` created by `unused` causes `collapse_vars` to misbehave.

fixes #2846
2018-01-26 14:21:11 +08:00
Alex Lam S.L
95cfce68ea backport of #2835 (#2841) 2018-01-23 05:45:45 +08:00
Alex Lam S.L
ec4202590d drop assignments to constant expressions only (#2839)
fixes #2838
2018-01-23 02:49:54 +08:00
Alex Lam S.L
5e2cd07d6f handle duplicate function declarations correctly (#2837)
fixes #2836
2018-01-23 01:28:09 +08:00
Alex Lam S.L
06166df999 v3.3.8 2018-01-21 07:08:01 +00:00
Alex Lam S.L
e2dc9cf091 fix unsafe evaluate of AST_Array (#2825)
fixes #2822
2018-01-21 01:39:44 +08:00
Alex Lam S.L
069df27bf1 enable unsafe for test/ufuzz.js (#2819)
- introduce `unsafe_undefined`
- safer `.toString()` compression

Miscellaneous
- rename `unsafe_Function`
2018-01-19 23:47:42 +08:00
Alex Lam S.L
3e7873217c improve unused on built-in functions (#2817) 2018-01-19 20:41:57 +08:00
Alex Lam S.L
e21bab7ce6 avoid duplicate property names in object literals under "use strict" (#2818)
fixes #2816
2018-01-19 20:13:50 +08:00
Alex Lam S.L
ac9a168fba fix & improve test/ufuzz.js (#2815)
- use correct `options` when testing `rename`
- mask arbitrarily assigned function IDs to reduce rate of false positives
2018-01-19 16:51:59 +08:00
Alex Lam S.L
81b64549ce fix time-out for respawned test/ufuzz.js (#2814) 2018-01-19 06:11:19 +08:00
Alex Lam S.L
082e004b87 compress undefined property names (#2811)
- enforce property names as string
- handle `void 0` as `undefined` in `hoist_props` & `reduce_vars`
2018-01-19 00:36:30 +08:00
kzc
983e69128b fix join_vars property assignment for negative array index (#2810)
fixes #2790
2018-01-18 21:52:54 +08:00
Alex Lam S.L
b335912e86 enhance test/ufuzz.js (#2808)
- standalone test for `rename`
- handle `keep_fargs` & `rename` upon failure
2018-01-18 14:08:05 +08:00
Alex Lam S.L
cc07f3b806 faster output of comments (#2806) 2018-01-18 02:57:33 +08:00
Alex Lam S.L
07e4b64f3a fix AST_Scope.clone() (#2803)
fixes #2799
2018-01-17 21:33:13 +08:00
Alex Lam S.L
d3ce2bc9e7 suppress unsafe_proto for LHS expressions (#2804) 2018-01-17 20:41:51 +08:00
Alex Lam S.L
cff3bf4914 configure rename with CLI (#2802) 2018-01-17 15:12:22 +08:00
Alex Lam S.L
79cfac77bd extend join_vars & sequences (#2798) 2018-01-17 13:58:27 +08:00
Alex Lam S.L
224c14d49d improve mocha tests (#2797)
- workaround sporadic delays from Travis CI
2018-01-16 17:51:25 +08:00
Alex Lam S.L
7857354d85 improve test/travis-ufuzz.js (#2795)
- print usage
- support concurrent jobs
- improve instance utilisation
- resume after V8 self-destruct
2018-01-16 17:33:21 +08:00
Alex Lam S.L
b4aef753e7 general improvements around AST_ForIn (#2796)
- compress using `collapse_vars`
- remove unused `name`
- simplify `loop_body`
2018-01-16 17:03:12 +08:00
Joël Galeran
424173d311 fix typo in README (#2792) 2018-01-16 10:29:38 +08:00
Alex Lam S.L
ec7cd1dcf7 handle VM failure gracefully (#2791) 2018-01-15 23:41:39 +08:00
Alex Lam S.L
7def684730 improve test/travis-ufuzz.js (#2789)
- wait for instance to boot
- run on forked repositories
- workaround `request_limit_reached`
2018-01-15 19:18:21 +08:00
Alex Lam S.L
10f961c27b enhance collapse_vars (#2788) 2018-01-15 18:47:23 +08:00
Alex Lam S.L
b483678ca7 avoid suboptimal termination in passes (#2787) 2018-01-15 16:42:31 +08:00
Alex Lam S.L
cbbe6fad60 avoid double counting within single-use functions (#2785)
fixes #2783
2018-01-15 16:42:15 +08:00
Alex Lam S.L
f96929c031 improve test/travis-ufuzz.js (#2786)
- use more RAM
- show progress in console
- report failure as job status
2018-01-15 15:08:35 +08:00
Alex Lam S.L
2b6657e967 run test/ufuzz.js when Travis CI is idle (#2784) 2018-01-15 08:52:11 +08:00
Alex Lam S.L
7c0c92943f v3.3.7 2018-01-14 09:13:26 +00:00
Alex Lam S.L
62a66dfff4 fix & extend join_vars for object assigments (#2781) 2018-01-14 17:11:31 +08:00
kzc
2cab348341 improve SymbolDef info in --output ast (#2778)
* SymbolDef info (a.k.a. `thedef`) is now represented as a string containing `"ID name [mangled_name]"`. 
* Enhance display of `globals`, `variables`, `functions` and `enclosed`.
* `SymbolDef.next_id` starts at `1` and the `id` is adjusted for `-o ast` display.
2018-01-14 01:40:51 +08:00
Alex Lam S.L
460218a3f8 v3.3.6 2018-01-13 05:37:42 +00:00
Alex Lam S.L
e49416e4aa fix reduce_vars on AST_Accessor (#2776)
fixes #2774
2018-01-13 02:46:14 +08:00
kzc
d4d7d99b70 add SymbolDef IDs to --output ast (#2772) 2018-01-12 15:41:09 +08:00
Alex Lam S.L
6a696d0a7b fix output of imported AST (#2771) 2018-01-12 01:05:49 +08:00
Alex Lam S.L
1c9e13f47d update dependencies (#2770)
- acorn@5.3.0
- commander@2.13.0
2018-01-12 00:32:17 +08:00
Alex Lam S.L
b757450cd8 fix nested unused assignments (#2769)
fixes #2768
2018-01-11 23:13:44 +08:00
Alex Lam S.L
23ec484806 fix corner case in #2763 (#2766) 2018-01-11 21:18:08 +08:00
Alex Lam S.L
f1e1bb419a join object assignments (#2763) 2018-01-11 17:08:21 +08:00
Alex Lam S.L
6a0af85c8b skip only vars in if_return (#2759)
fixes #2747
2018-01-10 19:08:46 +08:00
Alex Lam S.L
09269be974 enhance conditionals (#2758)
`x ? y || z : z` --> `x && y || z`
2018-01-10 16:59:57 +08:00
Alex Lam S.L
bf832cde16 improve synergy between compress and rename (#2755) 2018-01-09 17:55:41 +08:00
Alex Lam S.L
2972d58dbb patch variable declaractions extracted within catch (#2753)
fixes #2749
2018-01-09 13:54:35 +08:00
Alex Lam S.L
2e22d38a02 improve rename reproducibility (#2754)
fixes #2752
2018-01-09 13:53:05 +08:00
Alex Lam S.L
ce27bcd69a compress loops with immediate break (#2746)
fixes #2740
2018-01-08 14:30:18 +08:00
Alex Lam S.L
9336cc8247 v3.3.5 2018-01-07 11:51:36 +00:00
Alex Lam S.L
9809567dfc improve process.exit() workaround (#2741)
- use public API
- fix issue with Node.js 0.10 on WIndows
2018-01-07 17:53:50 +08:00
Alex Lam S.L
1ee8be8d91 fix recursive function inline (#2738)
fixes #2737
2018-01-07 15:31:24 +08:00
Alex Lam S.L
8430c2f9f8 enable AppVeyor CI (#2739) 2018-01-07 14:14:58 +08:00
Alex Lam S.L
659c8a7632 handle trailing line comments correctly (#2736)
fixes #2734
2018-01-06 21:05:21 +08:00
Alex Lam S.L
3564b4f20d compress RegExp() in unsafe (#2735) 2018-01-06 21:04:47 +08:00
Alex Lam S.L
3505a3604a enhance unsafe_proto (#2733) 2018-01-06 06:16:51 +08:00
kzc
9b1bc6c014 ufuzz: add strings "a", "b", "c" to VALUES (#2732) 2018-01-06 05:54:53 +08:00
Alex Lam S.L
9f23185f2b fix corner case with arguments as function name (#2729)
fixes #2728
2018-01-05 22:21:18 +08:00
Alex Lam S.L
b82feb9302 improve if_return (#2727) 2018-01-05 20:24:30 +08:00
Alex Lam S.L
7f2a591c7e warn on deprecated features (#2726)
- `function.arguments`
- `function.callers`

fixes #2719
2018-01-05 19:36:02 +08:00
Alex Lam S.L
afbcebddf6 fix mangle name collision across files (#2722) 2018-01-05 05:08:09 +08:00
Alex Lam S.L
484e484571 fix corner case in inline (#2720) 2018-01-04 23:38:37 +08:00
Alex Lam S.L
6f3f21233f reminify tests upon expect_stdout (#2716) 2018-01-04 20:13:05 +08:00
Alex Lam S.L
a6873a3859 forbid block-scoped AST_Defun in strict mode (#2718) 2018-01-04 18:45:51 +08:00
Alex Lam S.L
7a6d452b54 preserve constant modification under strict mode (#2717) 2018-01-04 15:53:53 +08:00
Alex Lam S.L
9b58b54e2d extend inline (#2714)
- compress `function` with variables within loops
- restrict to `AST_Var` for better compatibility with ES6+
2018-01-04 12:58:40 +08:00
Alex Lam S.L
c598a12af9 apply collapse_vars to loop conditions (#2712) 2018-01-04 03:18:28 +08:00
Alex Lam S.L
cfe3a98ce5 drop unused assignment based on reduce_vars (#2709) 2018-01-04 01:03:33 +08:00
Alex Lam S.L
14778e049b fix reduce_vars on AST_Defun (#2708) 2018-01-03 17:18:38 +08:00
Alex Lam S.L
446fb0198b extend __PURE__ to AST_New (#2706)
fixes #2705
2018-01-03 04:48:07 +08:00
Alex Lam S.L
7d3cddf9d6 inline functions with AST_Var (#2688) 2018-01-03 01:54:44 +08:00
Alex Lam S.L
6dead95eb3 enhance collapse_vars (#2704) 2018-01-02 18:42:15 +08:00
Alex Lam S.L
cc931b3ad8 enhance if_return (#2703) 2018-01-02 15:09:51 +08:00
Alex Lam S.L
d838b4b52e reset argument value within loop after inline (#2699) 2018-01-02 01:24:53 +08:00
Alex Lam S.L
2f3bddbaca scan within IIFEs of assigned values (#2702)
fixes #2701
2018-01-02 01:24:23 +08:00
Alex Lam S.L
673b071637 enhance join_vars & sequences (#2697)
- nudge declarations without assignments
  - within `AST_BlockStatement`
  - across `AST_If`
2018-01-01 00:09:26 +08:00
Alex Lam S.L
da82fa59a7 fix inline on duplicate argument names (#2698) 2017-12-31 20:59:58 +08:00
Alex Lam S.L
333792352e reduce hoisting declarations (#2687) 2017-12-31 16:15:00 +08:00
Alex Lam S.L
e2ec270b04 v3.3.4 2017-12-31 00:01:14 +08:00
Alex Lam S.L
ed7a0a454e fix dead_code on escaped return assignment (#2693)
fixes #2692
2017-12-30 15:20:25 +08:00
Alex Lam S.L
d819559a01 minor clean-ups (#2686) 2017-12-29 14:04:52 +08:00
Alex Lam S.L
8ca49155a8 v3.3.3 2017-12-29 03:07:39 +08:00
Alex Lam S.L
b95e3338d9 fix pure_getters on AST_Binary (#2681)
fixes #2678
2017-12-28 17:01:01 +08:00
Alex Lam S.L
e40a0ee9c6 improve assignment variations (#2671) 2017-12-28 15:36:55 +08:00
Alex Lam S.L
cb62bd98d3 fix function inlining within loops (#2675)
fixes #2663
2017-12-28 02:53:14 +08:00
Alex Lam S.L
f30790b11b fix dead_code on return assignments (#2668)
fixes #2666
2017-12-27 07:40:34 +08:00
Alex Lam S.L
5205dbcbf4 retain recursive function names (#2667)
fixes #2665
2017-12-27 07:00:12 +08:00
Alex Lam S.L
3ff625de7e fix bugs on substituted AST_Defun (#2661)
fixes #2660
2017-12-27 05:31:37 +08:00
Alex Lam S.L
4832bc5d88 replace single-use recursive functions (#2659)
fixes #2628
2017-12-26 21:25:35 +08:00
Alex Lam S.L
7f342cb3e3 suppress inline within substituted AST_Scope (#2658)
fixes #2657
2017-12-26 18:56:59 +08:00
Alex Lam S.L
05e7d34ed4 improve unused over duplicate variable names (#2656) 2017-12-26 18:29:28 +08:00
Alex Lam S.L
86607156e3 v3.3.2 2017-12-26 01:38:56 +08:00
Alex Lam S.L
0fe259e9c5 parse LF & comment correctly (#2653)
fixes #2652
2017-12-26 01:38:01 +08:00
Alex Lam S.L
8701a99a15 v3.3.1 2017-12-25 03:08:28 +08:00
Alex Lam S.L
1476c78b53 add html-minifier to benchmarks (#2646) 2017-12-25 03:07:46 +08:00
Alex Lam S.L
cb6a92892f fix infinite loop during inline (#2645)
fixes #2644
2017-12-25 01:57:11 +08:00
Alex Lam S.L
f1556cb945 v3.3.0 2017-12-24 17:34:56 +08:00
Alex Lam S.L
efffb81735 fix comments output & improve /*@__PURE__*/
- fix whitespace around comments
- fix comment parsing around parentheses
- consider parentheses when parsing `/*@__PURE__*/`
- remove all `/*@__PURE__*/` on output

fixes #2638
2017-12-24 12:38:45 +08:00
Alex Lam S.L
202f90ef8f fix corner cases with collapse_vars, inline & reduce_vars (#2637)
fixes #2630
2017-12-24 01:24:12 +08:00
Alex Lam S.L
c07ea17c01 fix escape analysis on AST_PropAccess (#2636) 2017-12-24 00:36:46 +08:00
Alex Lam S.L
edb4e3bd52 make comments output more robust (#2633)
- improve handling of comments right after `return`
- retain comments after `OutputStream`
- preserve trailing comments
- fix handling of new line before comments
- handle comments around parentheses

fixes #88
fixes #112
fixes #218
fixes #372
fixes #2629
2017-12-22 04:59:54 +08:00
Alex Lam S.L
4113609dd4 extend test/ufuzz.js to inline & reduce_funcs (#2620)
- forward call `fN()`
- allow forward call functions to be single-use
- avoid generating `AST_Defun` within blocks
2017-12-20 23:52:18 +08:00
Alex Lam S.L
7ac7b0872f remove AST hack from inline (#2627) 2017-12-20 17:05:53 +08:00
Alex Lam S.L
86ae5881b7 disable hoist_funs by default (#2626) 2017-12-20 17:05:40 +08:00
Alex Lam S.L
fac003c64f avoid inline of function with special argument names (#2625) 2017-12-20 02:48:04 +08:00
Alex Lam S.L
2273655c17 fix inline after single-use reduce_vars (#2623) 2017-12-19 22:19:33 +08:00
Ondřej Španěl
01057cf76d Transform can be simplified when clone is not done. (#2621) 2017-12-19 17:56:16 +08:00
Alex Lam S.L
032f096b7f add test for #2613 (#2618) 2017-12-19 05:22:05 +08:00
Alex Lam S.L
4b334edf49 handle global constant collision with local variable after inline (#2617)
fixes #2616
2017-12-19 03:05:30 +08:00
Alex Lam S.L
8ddcbc39e6 compress apply() & call() of function (#2613)
- `fn.apply(a, [ ... ])` => `fn.call(a, ...)`
- `fn.call(a, ... )` => `a, fn(...)`

where `fn` can be `function` literal or symbol reference linked through `reduce_vars`
2017-12-18 16:23:39 +08:00
Alex Lam S.L
0b0eac1d5d drop property assignment to constants (#2612) 2017-12-18 12:07:53 +08:00
Alex Lam S.L
b29fc8b27c improve transversal efficiency in collapse_vars (#2611)
fixes #2603
2017-12-18 03:00:05 +08:00
Alex Lam S.L
5de369fa67 export parse() (#2608) 2017-12-17 23:12:23 +08:00
Alex Lam S.L
7918a50d52 improve reset_opt_flags() (#2610) 2017-12-17 23:01:08 +08:00
Alex Lam S.L
21794c9b8d account for catch variable when inline (#2605)
fixes #2604
2017-12-16 15:21:09 +08:00
Alex Lam S.L
6c686ce593 fix nested inline (#2602)
fixes #2601
2017-12-16 02:16:35 +08:00
Alex Lam S.L
db902af4c6 fix escape analysis on || and && (#2600)
fixes #2598
2017-12-15 19:48:14 +08:00
Alex Lam S.L
7d6907cb99 fix dead_code on nested try (#2599)
fixes #2597
2017-12-15 19:41:28 +08:00
Alex Lam S.L
092d9affb8 fix reduce_vars on do...while (#2596) 2017-12-15 16:33:19 +08:00
Alex Lam S.L
8f681b1d17 handle inline of function arguments (#2590)
fixes #2476
2017-12-15 13:28:30 +08:00
Alex Lam S.L
90313875f7 inline single-use function across loop (#2594) 2017-12-14 19:24:54 +08:00
Alex Lam S.L
3f18a61532 fix reduce_vars on single AST_Defun reference across loop (#2593) 2017-12-14 18:47:05 +08:00
Alex Lam S.L
02a6ce07eb improve reduce_vars (#2592)
- account for hoisting nature of `var`
2017-12-14 15:32:13 +08:00
Alex Lam S.L
738fd52bc4 improve collapse_vars (#2591)
- handle single-use assignments other than `AST_VarDef`
- scan `AST_Call` for candidates
2017-12-14 15:31:35 +08:00
kzc
d18979bb23 improve dead_code tests (#2589)
for #2588
2017-12-14 12:12:06 +08:00
Alex Lam S.L
8266993c6e fix dead_code on return/throw within try (#2588) 2017-12-14 04:38:21 +08:00
Alex Lam S.L
9a137e8613 drop local assign-only variable in return (#2587) 2017-12-14 02:59:59 +08:00
Alex Lam S.L
ef618332ea fold cascade functionality into collapse_vars (#2586) 2017-12-14 01:20:36 +08:00
Alex Lam S.L
7f418978c9 recover lost opportunities from #2574 (#2584) 2017-12-13 18:20:53 +08:00
Alex Lam S.L
04cc395c35 improve collapse_vars on side-effect-free replacements (#2583) 2017-12-13 04:52:54 +08:00
Alex Lam S.L
e008dc1bde minor clean-up for IIFE (#2582)
- faster exact type match
- aggressively convert to `!`
2017-12-13 01:27:26 +08:00
Alex Lam S.L
ddf96cfda2 avoid Function.prototype pollution by test/sandbox.js (#2581) 2017-12-12 05:02:01 +08:00
Alex Lam S.L
ebfd5c5c74 fix AST_VarDef.may_throw() (#2580) 2017-12-12 03:30:25 +08:00
Alex Lam S.L
f2ad542679 fix collapse_vars on switch (#2578) 2017-12-11 18:11:09 +08:00
Alex Lam S.L
c43118be4f remove unused code (#2579)
fixes #2577
2017-12-11 17:39:08 +08:00
Alex Lam S.L
93f3b2b114 escape consecutive unpaired surrogates (#2576)
fixes #2569
2017-12-11 01:15:44 +08:00
Alex Lam S.L
bf000beae7 rename tests (#2575) 2017-12-11 00:24:54 +08:00
Alex Lam S.L
0e16d92786 handle exceptional flow correctly in collapse_vars (#2574)
fixes #2571
2017-12-11 00:16:02 +08:00
Alex Lam S.L
2441827408 v3.2.2 2017-12-10 13:46:17 +08:00
Alex Lam S.L
0aff037a35 improve unused on assign-only symbols (#2568) 2017-12-09 06:19:29 +08:00
Alex Lam S.L
74a2f53683 fix escape analysis for AST_Throw (#2564) 2017-12-08 02:54:37 +08:00
Alex Lam S.L
e20935c3f2 fix escape analysis for AST_Conditional & AST_Sequence (#2563)
fixes #2560
2017-12-08 01:50:38 +08:00
Alex Lam S.L
3e34f62a1c account for side-effects in conditional call inversion (#2562)
fixes #2560
2017-12-08 01:15:31 +08:00
Alex Lam S.L
d21cb84696 eliminate noop calls more aggressively (#2559) 2017-12-07 01:22:08 +08:00
Alex Lam S.L
3dd495ecdd improve if_return (#2558)
`return void x()` => `x()`
2017-12-07 01:01:52 +08:00
Alex Lam S.L
b9f3ddfb30 v3.2.1 2017-12-03 11:39:51 +08:00
Alex Lam S.L
77332a0315 fix dead_code on for (#2552) 2017-12-02 15:46:05 +08:00
Alex Lam S.L
85c56adbd1 more tests for #2535 (#2551) 2017-12-02 02:26:56 +08:00
Alex Lam S.L
8da3754e51 improve evaluate on typeof (#2550)
- gated through `typeofs`
2017-12-02 02:18:33 +08:00
Alex Lam S.L
9a6b11f8e6 improve boolean compression (#2548)
fixes #2535
2017-12-01 22:41:35 +08:00
Alex Lam S.L
7ac6fdcc99 improve switch case compression (#2547) 2017-12-01 14:32:00 +08:00
Alex Lam S.L
f6610baaa8 improve AST_For.init & AST_Switch.expression compression (#2546) 2017-12-01 12:53:59 +08:00
Alex Lam S.L
09b320e8a5 convert to number under boolean context (#2545) 2017-12-01 12:52:36 +08:00
Alex Lam S.L
5a1e99d713 improve compression of if conditions (#2544) 2017-12-01 06:18:31 +08:00
Alex Lam S.L
b762f2d6f4 improve compression of loop conditions (#2543) 2017-12-01 05:52:33 +08:00
Alex Lam S.L
172079a47f improve code reuse (#2542) 2017-12-01 03:40:46 +08:00
Alex Lam S.L
c58d3936a3 fix corner case in call binding (#2541) 2017-12-01 03:18:20 +08:00
Alex Lam S.L
18302bf8e9 backport test from #2526 (#2534) 2017-11-29 13:32:00 +08:00
Alex Lam S.L
bc5047c1e7 fix inline on nested substitutions (#2533)
fixes #2531
2017-11-29 13:31:41 +08:00
Alex Lam S.L
206a54a746 fix nested hoist_props substitution (#2523)
fixes #2519
2017-11-28 14:39:00 +08:00
Alex Lam S.L
32def5ebf5 improve synergy between collapse_vars & unused (#2521) 2017-11-28 14:02:39 +08:00
Alex Lam S.L
ecc9f6b770 drop assignment in AST_VarDef.value (#2522)
fixes #2516
2017-11-28 13:08:40 +08:00
Alex Lam S.L
b37a68c84f v3.2.0 2017-11-26 04:08:35 +08:00
Alex Lam S.L
c141ae6f8d fix argument/atom collision by properties (#2514)
fixes #2513
2017-11-25 22:52:46 +08:00
Alex Lam S.L
97c464dbf5 fix wording and formatting (#2512) 2017-11-25 19:07:46 +08:00
Alex Lam S.L
3b28b915eb extend escape analysis on constant expression properties (#2509)
fixes #2508
2017-11-24 14:07:39 +08:00
Alex Lam S.L
eb001dc1d9 fix argument/atom collision by collapse_vars (#2507)
fixes #2506
2017-11-24 07:26:22 +08:00
Alex Lam S.L
aa9bdf416e make AST_Lambda.contains_this() less magical (#2505) 2017-11-24 07:03:37 +08:00
Alex Lam S.L
8987780db6 eliminate invalid state caching in collapse_vars (#2502)
fixes #2497
2017-11-24 04:12:37 +08:00
Alex Lam S.L
30cfea2e7a fix rename (#2501)
- suppress spurious `rename` from `commander`
- handle `AST_SymbolCatch` correctly
2017-11-24 03:05:43 +08:00
Alex Lam S.L
f4e2fb9864 expand symbol space to improve compression (#2460)
- give globally distinct names to distinct variables
- improve ability to compress cross-scoped
- introduce `options.rename` to `minify()`
- default `true` if both `compress` & `mangle`
2017-11-19 19:29:51 +08:00
Alex Lam S.L
b80062c490 enable hoist_props by default (#2492) 2017-11-19 14:56:23 +08:00
Alex Lam S.L
667fc4d08b v3.1.10 2017-11-18 23:56:33 +08:00
kzc
6142117cdd document the webkit output option (#2490)
- workaround for WebKit bugs
- PhantomJS users should enable this output option

closes #2489
2017-11-17 13:46:49 +08:00
Alex Lam S.L
ae28a24c7f fix cross-scope inlining of AST_Functions (#2486)
fixes #2485
2017-11-16 10:04:30 +08:00
Alex Lam S.L
ebe761cad0 minor consolidations (#2484)
- unique symbol generation
- `unsafe` on `AST_Call`
2017-11-16 04:37:37 +08:00
kzc
fa7a7c5c5a Update ISSUE_TEMPLATE.md (#2481) 2017-11-15 06:00:51 +08:00
kzc
557636f3b7 update documentation for reduce_funcs (#2478) 2017-11-14 16:03:25 +08:00
Alex Lam S.L
49fbe9c5ac fix replacement logic in collapse_vars (#2475) 2017-11-13 07:37:42 +08:00
Alex Lam S.L
2ac5086831 fix top_retain on hoist_props (#2474)
fixes #2473
2017-11-13 00:59:41 +08:00
Alex Lam S.L
c6cfa04d10 allow symbol replacement on multiple occurrences (#2472)
- all-or-nothing replacement
- avoid unmangleable names

fixes #2436
2017-11-12 22:31:47 +08:00
Alex Lam S.L
346fa12e0e v3.1.9 2017-11-11 15:31:13 +08:00
Alex Lam S.L
cda27b0970 extend reduce_funcs to cover cross-scope substitutions (#2469)
fixes #2468
2017-11-11 15:30:17 +08:00
Alex Lam S.L
3c74047368 implement compress option reduce_funcs (#2466)
- inline single-use function declarations as expressions when permissible
- depend on `reduce_vars`
- enabled by default
- disable for speed critical code

fixes #2464
2017-11-11 05:59:35 +08:00
Alex Lam S.L
94525d859f fix object literal tracing in reduce_vars (#2461) 2017-11-10 05:47:10 +08:00
Alex Lam S.L
1127a2caf3 fix multiple nested function substitutions (#2458)
fixes #2449
2017-11-09 23:30:00 +08:00
Alex Lam S.L
246d9d4e83 remove hack in collapse_vars (#2457)
fixes #2456
2017-11-09 20:00:58 +08:00
Alex Lam S.L
4c0b0177b6 preserve function identity in reduce_vars (#2451)
fixes #2450
2017-11-08 03:28:46 +08:00
Alex Lam S.L
38bfb73f06 v3.1.8 2017-11-07 03:55:16 +08:00
Alex Lam S.L
bbedbf4ea0 handle circular function reference gracefully (#2446)
fixes #2442
2017-11-07 02:37:23 +08:00
Alex Lam S.L
2cfb5aa7da account for eval & with in reduce_vars (#2441)
fixes #2440
2017-11-06 16:10:57 +08:00
Alex Lam S.L
6c45101870 consolidate & enhance unused (#2439)
- defer declaration removal in `collapse_vars`
- account for `AST_SymbolFunarg` in deduplication
- private accounting for `collapse_vars`
- avoid issues with identity reference due to deep cloning

fixes #2437
2017-11-06 14:25:10 +08:00
Alex Lam S.L
2c2fd89e34 inline single-use functions that are not constant expressions (#2434)
fixes #2428
2017-11-05 22:14:11 +08:00
Alex Lam S.L
f46281e2b7 v3.1.7 2017-11-05 15:03:19 +08:00
Alex Lam S.L
25a18883f5 tweak #2424 (#2432) 2017-11-05 12:49:14 +08:00
Alex Lam S.L
5b4b07e9a7 extend function inlining safety checks (#2430) 2017-11-05 06:18:45 +08:00
Alex Lam S.L
a8aa28a7a6 consolidate single-use function reduction (#2427)
fixes #2423
2017-11-05 04:27:01 +08:00
Alex Lam S.L
fe5a68f9d5 maintain call argument order in collapse_vars (#2426)
fixes #2425
2017-11-05 00:00:18 +08:00
Alex Lam S.L
71e61153b1 improve variations on call arguments for ufuzz (#2424) 2017-11-04 16:29:42 +08:00
Alex Lam S.L
c8b6f4733d reduce this within functions (#2421)
- only replace same-scope usages
- augment `test/ufuzz.js` to test for `this`


fixes #2420
2017-11-04 00:31:37 +08:00
Alex Lam S.L
a48f87abf2 compress new function containing this (#2417) 2017-10-30 23:19:27 +08:00
Alex Lam S.L
2fd927a7cc v3.1.6 2017-10-29 12:38:10 +08:00
Alex Lam S.L
8428326ea1 enhance properties (#2412)
- trim array items only if `side_effects`
- extend to non-identifier properties
2017-10-29 04:11:26 +08:00
Alex Lam S.L
31f8209193 remove dead code (#2405) 2017-10-27 14:28:09 +08:00
Alex Lam S.L
9b0f86f5a1 fix reduce_vars on AST_Array.length (#2404) 2017-10-27 02:33:37 +08:00
Alex Lam S.L
ee082ace1b compress self comparisons (#2398) 2017-10-26 01:16:12 +08:00
kzc
ae67a49850 document compress option hoist_props (#2399) 2017-10-25 14:03:43 +08:00
Alex Lam S.L
4178289c38 implement hoist_props (#2396)
fixes #2377
2017-10-25 03:38:11 +08:00
Alex Lam S.L
74ae16f9f8 fix unsafe reduce_vars on arrays & objects (#2397) 2017-10-24 22:10:36 +08:00
Tom MacWright
1968203d83 docs: Fix spelling and style (#2395) 2017-10-24 04:59:12 +08:00
Alex Lam S.L
86ea38a259 enhance unsafe evaluate of arrays & objects (#2394) 2017-10-24 02:58:30 +08:00
Alex Lam S.L
8a713e449f deduplicate declarations regardless of toplevel (#2393) 2017-10-23 01:00:50 +08:00
Alex Lam S.L
24aa07855b safer properties transform (#2391)
`{ a: x, b: y }.a` => `[ x, y ][0]`
- `x` cannot be function containing `this`

`[ x, y, z ][1]` => `(x, z, y)`
- only if `z` is side-effect-free
2017-10-22 20:10:13 +08:00
Alex Lam S.L
5fd723f143 fix unsafe expansion of object literals (#2390) 2017-10-22 15:00:36 +08:00
Alex Lam S.L
516eaef50c fix unsafe evaluation of AST_Sub (#2389) 2017-10-22 13:14:15 +08:00
Alex Lam S.L
4ae1fb3ed8 fix unsafe evaluation of objects (#2388) 2017-10-22 04:19:40 +08:00
Alex Lam S.L
011123223b fix unsafe escape analysis in reduce_vars (#2387) 2017-10-22 03:23:31 +08:00
Alex Lam S.L
96439ca246 v3.1.5 2017-10-22 00:27:26 +08:00
Alex Lam S.L
c927cea632 unsafe fix-ups for #2351 (#2379) 2017-10-21 04:08:26 +08:00
Alex Lam S.L
9f4b98f8e4 backport #2374 (#2376) 2017-10-19 23:02:27 +08:00
Alex Lam S.L
0f2ef3367c enhance collapse_vars around lazy operations (#2369) 2017-10-19 04:52:00 +08:00
Alex Lam S.L
7e5b5cac97 fix AST_PropAccess in collapse_vars (take 3) (#2375)
Suppress scanning beyond assignment to `a.b`
2017-10-18 02:54:51 +08:00
Alex Lam S.L
c1346e06b7 clean up lazy operator detection (#2373) 2017-10-17 23:25:45 +08:00
Alex Lam S.L
0d2fe8e3ef fix AST_PropAccess in collapse_vars (take 2) (#2372)
fixes #2364
2017-10-17 22:59:15 +08:00
Alex Lam S.L
f2b9c11e2a fix AST_PropAccess in collapse_vars (#2370)
fixes #2364
2017-10-17 18:33:03 +08:00
Alex Lam S.L
fe647b083e account for side-effects from AST_This in collapse_vars (#2365) 2017-10-17 01:18:55 +08:00
Alex Lam S.L
dfe4f6c6de v3.1.4 2017-10-16 02:44:17 +08:00
Alex Lam S.L
a09c8ad666 update dependency (#2362)
- source-map@0.6.1
2017-10-16 02:41:22 +08:00
Alex Lam S.L
ec598c351b fix-ups for #2356 (#2360) 2017-10-15 22:33:55 +08:00
Alex Lam S.L
eba0f93bc0 more tests for #2351 (#2357) 2017-10-12 02:58:25 +08:00
Roger Peppe
99800d4aa9 update README to include defaults (#2356)
fixes #2353
2017-10-12 02:56:02 +08:00
Tim Malone
70d56c951a Update README.md - sourceMappingURL directive note (#2355)
Moves this README note to underneath the 'url' rather than 'root' option.
2017-10-11 19:48:43 +08:00
Alex Lam S.L
b810e2f8da perform reduce_vars on safe literals (#2351)
- constant expression
- single reference
- same scope
- not across loop body
2017-10-09 12:25:06 +08:00
Alex Lam S.L
1abe14296e collapse a.b whenever safe (#2350) 2017-10-08 13:17:48 +08:00
Alex Lam S.L
6920e898d1 v3.1.3 2017-10-01 12:36:07 +08:00
Alex Lam S.L
dd71639264 enhance reduce_vars for AST_Accessor (#2339)
fixes #2336
2017-10-01 03:01:50 +08:00
Alex Lam S.L
2dcc552ce0 trap invalid use of reserved words (#2338)
fixes #2337
2017-10-01 02:10:41 +08:00
Alex Lam S.L
55387e8fd0 v3.1.2 2017-09-24 02:02:04 +08:00
kzc
7e3e9da860 fix "use asm" numeric output (#2328)
fixes #2324
2017-09-21 04:42:40 +08:00
Alex Lam S.L
00f509405b suppress collapse_vars of this into "use strict" (#2326)
fixes #2319
2017-09-20 05:23:20 +08:00
Alex Lam S.L
aceb0af36b v3.1.1 2017-09-17 04:36:27 +08:00
Alex Lam S.L
4f0953f7e9 handle LHS side-effects on cascade & collapse_vars (#2314)
fixes #2313
2017-09-16 11:45:19 +08:00
Alex Lam S.L
182a47bfb1 improve source mapping (#2312)
fixes #2310
2017-09-15 12:46:48 +08:00
Alex Lam S.L
cd27f4ec38 v3.1.0 2017-09-10 15:17:24 +08:00
Mateusz Burzyński
8158b1bdcf Testing all leading comments against being PURE comments (#2305) 2017-09-10 02:08:15 +08:00
Alex Lam S.L
aacf3edc68 extend unsafe on pure global functions (#2303) 2017-09-07 22:08:34 +08:00
kzc
8b89072190 add Date and other known globals to unsafe compress option (#2302) 2017-09-07 02:44:26 +08:00
Alex Lam S.L
395a17ccda fix collapse_vars on default function argument (#2299)
Avoid collision with local variable `undefined` under certain corner cases.

fixes #2298
2017-09-04 02:32:33 +08:00
Alex Lam S.L
3f355866cf correctly count declarations after hoist_vars (#2297)
fixes #2295
2017-09-03 17:23:31 +08:00
David Šanda
71d52f147d Fix CLI example for mangle reserved list of names (#2294) 2017-08-31 00:55:32 +08:00
David Šanda
eb7adaa6fc Fix CLI source-maps examples (#2291)
fixes #2284
2017-08-29 23:49:20 +08:00
Alex Lam S.L
e5cf7972ea fix unused patching of AST_For.init blocks (#2289)
fixes #2288
2017-08-29 01:10:04 +08:00
Alex Lam S.L
f81ff10a9b v3.0.28 2017-08-20 00:27:01 +08:00
Erik Desjardins
16d40915b4 don't escape null characters as \0 when followed by any digit (#2273)
fixes #2272
2017-08-14 12:30:08 +08:00
Alex Lam S.L
e7c21e87e3 fix ie8 mangling of top-level AST_SymbolCatch (#2263)
fixes #2254
2017-08-01 02:38:32 +08:00
Alex Lam S.L
c4c2ef44d0 v3.0.27 2017-07-30 01:50:42 +08:00
Alex Lam S.L
a845897758 improve mangle.properties (#2261)
- include dead code when `keep_quoted`
- unify `keep_quoted` & `reserved`
- make `test/run-tests.js` consistent with `minify()`

fixes #2256
2017-07-29 23:02:04 +08:00
kzc
32ea2c5530 issue template: describe acceptable JS input (#2255) 2017-07-27 21:38:36 +08:00
Alex Lam S.L
bc61deeca9 v3.0.26 2017-07-23 12:39:36 +08:00
Alex Lam S.L
6a5e74b44e unescape surrogate pairs only (#2246)
fixes #2242
2017-07-23 12:38:21 +08:00
Alex Lam S.L
54446341ee update dependencies (#2241)
- acorn@5.1.1
- commander@2.11.0
- mocha@3.4.2
2017-07-16 16:20:40 +08:00
Alex Lam S.L
4e12a6f740 v3.0.25 2017-07-16 11:05:53 +08:00
Alex Lam S.L
b35dfc2599 reject malformed CLI parameters (#2239)
fixes #2237
2017-07-15 23:50:27 +08:00
Alex Lam S.L
9e1da9235e ensure ie8 works with mangled properties (#2238)
fixes #2234
2017-07-15 22:50:59 +08:00
Alex Lam S.L
a5ffe2c23f drop unused builtin globals under unsafe (#2236)
fixes #2233
2017-07-15 15:16:11 +08:00
Alex Lam S.L
9282e7b0c6 fix unsafe evaluate of Object static methods (#2232)
fixes #2231
2017-07-14 19:52:01 +08:00
Alex Lam S.L
5229cb2b1b drop unused compound assignments (#2230)
fixes #2226
2017-07-14 00:39:34 +08:00
Alex Lam S.L
458e3e15f0 enhance passes (#2229)
- remove hardcoded upper limit
- continue based on node count reduction
- emit verbose statistics

fixes #2226
2017-07-13 02:18:59 +08:00
Alex Lam S.L
c615a1e80a fix gzip stream in test/benchmark.js (#2228) 2017-07-12 02:55:57 +08:00
Alex Lam S.L
10a938cb79 enhance source mapping on IIFEs (#2224)
fixes #2213
2017-07-11 02:34:28 +08:00
Alex Lam S.L
4956ad311b benchmark gzipped output (#2220) 2017-07-09 01:44:59 +08:00
kzc
145874e504 docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 01:06:15 +08:00
Alex Lam S.L
bd7be07c38 v3.0.24 2017-07-08 12:53:20 +08:00
Alex Lam S.L
71ee91e716 handle duplicate argument names in collapse_vars (#2215) 2017-07-08 04:42:35 +08:00
Alex Lam S.L
4f70d2e28c inlining of static methods & constants (#2211)
- guard by `unsafe`
- support `Array`, `Math`, `Number`, `Object` & `String`

fixes #2207
2017-07-07 05:35:32 +08:00
Alex Lam S.L
4b6ca5e742 inline property access of object literal (#2209)
- only if property value is side-effect-free
- guard by `unsafe`

fixes #2208
2017-07-06 21:51:58 +08:00
Alex Lam S.L
9306da3c58 suppress collapse_vars of this as call argument (#2204)
fixes #2203
2017-07-06 01:03:52 +08:00
Alex Lam S.L
1ac25fc032 improve compress granularity through typeofs (#2201)
fixes #2198
2017-07-05 19:20:33 +08:00
Alex Lam S.L
5f046c724b minor clean-ups to evaluate (#2197) 2017-07-03 18:52:39 +08:00
Alex Lam S.L
af0262b7e5 improve parenthesis emission (#2196)
- eliminate `throw` usages
- suppress extraneous parenthesis
  - `new function() {foo.bar()}.baz`
  - `for (function() { "foo" in bar; };;);`
2017-07-03 04:17:37 +08:00
Alex Lam S.L
6b3aeff1d8 clean up TreeWalker.pop() (#2195)
Remove superfluous parameter.
2017-07-03 03:23:38 +08:00
Alex Lam S.L
20e4f8277f refactor throw usage within compress (#2193)
Eliminate exceptional constructs from normal control flow.
2017-07-03 02:10:56 +08:00
kzc
f3a487a368 document fast mangle-only minify mode (#2194) 2017-07-03 01:37:04 +08:00
196 changed files with 48243 additions and 8223 deletions

View File

@@ -1,20 +1,25 @@
**Bug report or feature request?**
**Bug report or feature request?**
<!-- 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`)**
**JavaScript input** <!-- ideally as small as possible -->
**JavaScript input**
<!--
A complete parsable JS program exhibiting the issue with
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
Issues without a reproducible test case will be closed.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.**
**JavaScript output or error produced.**
<!--
Note: `uglify-js` only supports ES5.
Those wishing to minify ES6 should use `uglify-es`.
Note: `uglify-js` only supports JavaScript.
Those wishing to minify ES6+ should transpile first.
-->

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

@@ -0,0 +1,39 @@
name: CI
on: [ push, pull_request ]
jobs:
test:
strategy:
matrix:
node: [ "0.10", "0.12", "4", "6", "8", "10", latest ]
os: [ ubuntu-latest, windows-latest ]
script: [ compress, mocha, release/benchmark, 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 update-notifier false
npm --version
while !(npm install); do echo "'npm install' failed - retrying..."; done
node test/$TYPE

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

@@ -0,0 +1,33 @@
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 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

61
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,61 @@
Contributing
============
## Documentation
Every new feature and API change should be accompanied by a README additon.
## Testing
All features and bugs should have tests that verify the fix. You can run all
tests using `npm test`.
The most common type of test are tests that verify input and output of the
Uglify transforms. These tests exist in `test/compress`. New tests can be added
either to an existing file or in a new file `issue-xxx.js`.
Tests that cannot be expressed as a simple AST can be found in `test/mocha`.
## Code style
- File encoding must be `UTF-8`.
- `LF` is always used as a line ending.
- Statements end with semicolons.
- Indentation uses 4 spaces, switch `case` 2 spaces.
- Identifiers use `snake_case`.
- Strings use double quotes (`"`).
- Use a trailing comma for multiline array and object literals to minimize diffs.
- The Uglify code only uses ES5, even in the `harmony` branch.
- Line length should be at most 80 cols, except when it is easier to read a
longer line.
- If both sides of a comparison are of the same type, `==` and `!=` are used.
- Multiline conditions place `&&` and `||` first on the line.
**Example feature**
```js
OPT(AST_Debugger, function(self, compressor) {
if (compressor.option("drop_debugger"))
return make_node(AST_EmptyStatement, self);
return self;
});
```
**Example test case**
```js
drop_debugger: {
options = {
drop_debugger: true,
}
input: {
debugger;
if (foo) debugger;
}
expect: {
if (foo);
}
}
```

View File

@@ -1,6 +1,6 @@
UglifyJS is released under the BSD license:
Copyright 2012-2013 (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
modification, are permitted provided that the following conditions

440
README.md
View File

@@ -6,9 +6,8 @@ UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
#### Note:
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
- `uglify-js` only supports ECMAScript 5 (ES5).
- Those wishing to minify
ES2015+ (ES6+) should use the `npm` package [**uglify-es**](https://github.com/mishoo/UglifyJS2/tree/harmony).
- `uglify-js` only supports JavaScript (ECMAScript 5).
- To minify ECMAScript 2015 or above, transpile using tools like [Babel](https://babeljs.io/).
Install
-------
@@ -70,7 +69,7 @@ a double dash to prevent input files being used as option arguments:
`debug` Add debug prefix and suffix.
`domprops` Mangle property names that overlaps
with DOM properties.
`keep_quoted` Only mangle unquoted properies.
`keep_quoted` Only mangle unquoted properties.
`regex` Only mangle matched property names.
`reserved` List of names that should not be mangled.
-b, --beautify [options] Beautify output/specify output options:
@@ -88,6 +87,7 @@ a double dash to prevent input files being used as option arguments:
`wrap_iife` Wrap IIFEs in parenthesis. Note: you may
want to disable `negate_iife` under
compressor options.
-O, --output-opts [options] Specify output options (`beautify` disabled by default).
-o, --output <file> Output file path (default STDOUT). Specify `ast` or
`spidermonkey` to write UglifyJS or SpiderMonkey AST
as JSON to STDOUT respectively.
@@ -105,6 +105,8 @@ a double dash to prevent input files being used as option arguments:
sequences.
--config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions.
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
argument(s) & value(s).
--ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options.
@@ -119,7 +121,8 @@ a double dash to prevent input files being used as option arguments:
JS that was generated from some other original
code. Specify "inline" if the source map is
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
the content of source files in the
source map as sourcesContent property.
@@ -150,19 +153,21 @@ debugging your compressed JavaScript. To get a source map, pass
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.
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
`//# sourceMappingURL=` directive.
- `--source-map url=<URL>` to specify the URL where the source map can be found.
For example:
uglifyjs js/file1.js js/file2.js \
-o foo.min.js -c -m \
--source-map root="http://foo.com/src",url=foo.min.js.map
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
The above will compress and mangle `file1.js` and `file2.js`, will drop the
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
@@ -181,8 +186,8 @@ CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →
compressed JS by mapping every token in the compiled JS to its original
location.
To use this feature pass `--source-map content="/path/to/input/source.map"`
or `--source-map content=inline` if the source map is included inline with
To use this feature pass `--source-map "content='/path/to/input/source.map'"`
or `--source-map "content=inline"` if the source map is included inline with
the sources.
## CLI compress options
@@ -203,17 +208,15 @@ Example:
To enable the mangler you need to pass `--mangle` (`-m`). The following
(comma-separated) options are supported:
- `toplevel` mangle names declared in the top level scope (disabled by
default).
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
- `eval` mangle names visible in scopes where `eval` or `with` are used
(disabled by default).
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
When mangling is enabled but you want to prevent certain names from being
mangled, you can declare those names with `--mangle reserved` — pass a
comma-separated list of names. For example:
uglifyjs ... -m reserved=[$,require,exports]
uglifyjs ... -m reserved=['$','require','exports']
to prevent the `require`, `exports` and `$` names from being changed.
@@ -223,7 +226,7 @@ to prevent the `require`, `exports` and `$` names from being changed.
is a separate step, different from variable name mangling. Pass
`--mangle-props` to enable it. It will mangle all properties in the
input code with the exception of built in DOM properties and properties
in core javascript classes. For example:
in core JavaScript classes. For example:
```javascript
// example.js
@@ -238,7 +241,7 @@ x.bar_ = 2;
x["baz_"] = 3;
console.log(x.calc());
```
Mangle all properties (except for javascript `builtins`):
Mangle all properties (except for JavaScript `builtins`):
```bash
$ uglifyjs example.js -c -m --mangle-props
```
@@ -476,45 +479,47 @@ if (result.error) throw result.error;
## 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.
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
an object to specify [mangle options](#mangle-options) (see below).
- `mangle.properties` (default `false`) — a subcategory of the mangle option.
Pass an object to specify custom [mangle property options](#mangle-properties-options).
- `output` (default `null`) pass an object if you wish to specify
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
- `nameCache` (default `null`) -- pass an empty object `{}` or a previously
used `nameCache` object if you wish to cache mangled variable and
property names across multiple invocations of `minify()`. Note: this is
a read/write property. `minify()` will read the name cache state of this
object and update it during minification so that it may be
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.
- `parse` (default `{}`) — pass an object if you wish to specify some
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
```javascript
{
warnings: false,
parse: {
// parse options
},
@@ -537,6 +542,7 @@ if (result.error) throw result.error;
nameCache: null, // or specify a name cache object
toplevel: false,
ie8: false,
warnings: false,
}
```
@@ -590,107 +596,106 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Parse options
- `bare_returns` (default `false`) -- support top level `return` statements
- `html5_comments` (default `true`)
- `shebang` (default `true`) -- support `#!command` as the first line
## Compress options
- `sequences` (default: true) -- join consecutive simple statements using the
comma operator. May be set to a positive integer to specify the maximum number
of consecutive comma sequences that will be generated. If this option is set to
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
is grandfathered to be equivalent to `true` and as such means `200`. On rare
occasions the default sequences limit leads to very slow compress times in which
case a value of `20` or less is recommended.
- `arguments` (default: `true`) -- replace `arguments[index]` with function
parameter name whenever possible.
- `properties` -- rewrite property access using the dot notation, for
example `foo["bar"] → foo.bar`
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
- `dead_code` -- remove unreachable code
- `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c`
- `drop_debugger` -- remove `debugger;` statements
- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables,
side effects permitting.
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
e.g. `!(a <= b) → a > b`, attempts to negate binary nodes, e.g.
`a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to
allow improved compression. This might be unsafe when an at least one of two
operands is an object with computed values due the use of methods like `get`,
or `valueOf`. This could cause change in execution order after operands in the
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe_Func` (default: false) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
- `unsafe_math` (default: false) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_proto` (default: false) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
- `unsafe_regexp` (default: false) -- enable substitutions of variables with
`RegExp` values the same way as if they are constants.
- `conditionals` -- apply optimizations for `if`-s and conditional
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
expressions
- `comparisons` -- apply certain optimizations to binary nodes, for example:
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `dead_code` (default: `true`) -- remove unreachable code
- `evaluate` -- attempt to evaluate constant expressions
- `directives` (default: `true`) -- remove redundant or non-standard directives
- `booleans` -- various optimizations for boolean context, for example `!!a
? b : c → a ? b : c`
- `drop_console` (default: `false`) -- Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
statically determine the condition
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
- `unused` -- drop unreferenced functions and variables (simple direct variable
assignments do not count as references unless set to `"keep_assign"`)
- `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.
- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
in the top level scope (`false` by default, `true` to drop both unreferenced
functions and variables)
- `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
- `top_retain` -- prevent specific toplevel functions and variables from `unused`
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
- `functions` (default: `true`) -- convert declarations from `var`to `function`
whenever possible.
- `hoist_funs` -- hoist function declarations
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
- `hoist_funs` (default: `false`) -- hoist function declarations
- `hoist_props` (default: `true`) -- hoist properties from constant object and
array literals into regular variables subject to a set of constraints. For example:
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
and the `compress` option `toplevel` enabled.
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
by default because it seems to increase the size of the output in general)
- `if_return` -- optimizations for if/return and if/continue
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
- `inline` -- embed simple functions
- `inline` (default: `true`) -- inline calls to function with simple/`return` statement:
- `false` -- same as `0`
- `0` -- disabled inlining
- `1` -- inline simple functions
- `2` -- inline functions with arguments
- `3` -- inline functions with arguments and variables
- `true` -- same as `3`
- `join_vars` -- join consecutive `var` statements
- `join_vars` (default: `true`) -- join consecutive `var` statements
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()`
- `keep_fargs` (default: `strict`) -- Discard unused function arguments. Code
which relies on `Function.length` will break if this is done indiscriminately,
i.e. when passing `true`. Pass `false` to always retain function arguments.
- `collapse_vars` -- Collapse single-use non-constant variables - side
effects permitting.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle-options).
- `reduce_vars` -- Improve optimization on variables assigned with and
used as constant values.
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.
- `warnings` -- display warnings when dropping unreachable code or unused
declarations etc.
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
when we can statically determine the condition.
- `negate_iife` -- negate "Immediately-Called Function Expressions"
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the
code generator would insert.
- `pure_getters` -- the default is `false`. If you pass `true` for
this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`.
- `objects` (default: `true`) -- compact duplicate keys in object literals.
- `pure_funcs` -- default `null`. You can pass an array of names and
- `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
mind more passes will take more time.
- `properties` (default: `true`) -- rewrite property access using the dot notation, for
example `foo["bar"] → foo.bar`
- `pure_funcs` (default: `null`) -- You can pass an array of names and
UglifyJS will assume that those functions do not produce side
effects. DANGER: will not check if the name is redefined in scope.
An example case here, for instance `var q = Math.floor(a/b)`. If
@@ -699,50 +704,92 @@ 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
function won't produce any side effect, in which case the whole
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.
- `drop_console` -- default `false`. Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`.
- `expression` -- default `false`. Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
- `reduce_funcs` (default: `true`) -- Allows single-use functions to be
inlined as function expressions when permissible allowing further
optimization. Enabled by default. Option depends on `reduce_vars`
being enabled. Some code runs faster in the Chrome V8 engine if this
option is disabled. Does not negatively impact other major browsers.
- `keep_fargs` -- default `true`. Prevents the
compressor from discarding unused function arguments. You need this
for code which relies on `Function.length`.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values.
- `keep_fnames` -- default `false`. Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `sequences` (default: `true`) -- join consecutive simple statements using the
comma operator. May be set to a positive integer to specify the maximum number
of consecutive comma sequences that will be generated. If this option is set to
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
is grandfathered to be equivalent to `true` and as such means `200`. On rare
occasions the default sequences limit leads to very slow compress times in which
case a value of `20` or less is recommended.
- `passes` -- default `1`. Number of times to run compress with a maximum of 3.
In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time.
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
- `side_effects` (default: `true`) -- Pass `false` to disable potentially dropping
functions marked as "pure". A function call is marked as "pure" if a comment
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();`
- `strings` (default: `true`) -- compact string concatenations.
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
both unreferenced functions and variables)
- `top_retain` (default: `null`) -- prevent specific toplevel functions and
variables from `unused` removal (can be array, comma-separated, RegExp or
function. Implies `toplevel`)
- `typeofs` (default: `true`) -- Transforms `typeof foo == "undefined"` into
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
earlier versions due to known issues.
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
- `unsafe_comps` (default: `false`) -- compress expressions like `a <= b` assuming
none of the operands can be (coerced to) `NaN`.
- `unsafe_Function` (default: `false`) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
- `unsafe_math` (default: `false`) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_proto` (default: `false`) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
`RegExp` values the same way as if they are constants.
- `unsafe_undefined` (default: `false`) -- substitute `void 0` if there is a
variable named `undefined` in scope (variable name will be mangled, typically
reduced to a single character)
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`)
## Mangle options
- `reserved` (default `[]`). Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`.
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
top level scope.
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
- `keep_fnames` (default `false`) -- Pass `true` to not mangle function names.
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
[compress option](#compress-options).
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `reserved` (default `[]`) -- Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`.
- `toplevel` (default `false`) -- Pass `true` to mangle names declared in the
top level scope.
Examples:
@@ -768,16 +815,20 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
### Mangle properties options
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
`reserved` array.
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
names matching the regular expression.
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
- `debug` (default: `false`) -— Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
DOM properties. Not recommended to override this setting.
- `debug` (default: `false`) -— Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
names matching the regular expression.
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
`reserved` array.
## Output options
The code generator tries to output shortest code possible by default. In
@@ -786,31 +837,49 @@ can pass additional arguments that control the code output:
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
regexps (affects directives with non-ascii characters becoming invalid)
- `beautify` (default `true`) -- whether to actually beautify the output.
Passing `-b` will set this to true, but you might need to pass `-b` even
when you want to generate minified code, in order to specify additional
arguments, so you can use `-b beautify=false` to override it.
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
- `braces` (default `false`) -- always insert braces in `if`, `for`,
`do`, `while` or `with` statements, even if their body is a single
statement.
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
comments, `"some"` to preserve some comments, a regular expression string
(e.g. `/^!/`) or a function.
- `indent_level` (default 4)
- `indent_start` (default 0) -- prefix all lines by that many spaces
- `inline_script` (default `false`) -- escape the slash in occurrences of
`</script` in strings
comments, `"some"` to preserve multi-line comments that contain `@cc_on`,
`@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_start` (default `0`) -- prefix all lines by that many spaces
- `inline_script` (default `true`) -- escape HTML comments and the slash in
occurrences of `</script>` in strings
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
quotes from property names in object literals.
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
- `preamble` (default `null`) -- when passed it must be a string and
it will be prepended to the output literally. The source map will
adjust for this text. Can be used to insert a comment containing
licensing information, for example.
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
only works if `beautify` is set to `false`.
- `preserve_line` (default `false`) -- pass `true` to retain line numbering on
a best effort basis.
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
objects
- `quote_style` (default `0`) -- preferred quote style for strings (affects
quoted property names and directives as well):
- `0` -- prefers double quotes, switches to single quotes when there are
@@ -818,16 +887,23 @@ can pass additional arguments that control the code output:
- `1` -- always use single quotes
- `2` -- always use double quotes
- `3` -- always use the original quotes
- `semicolons` (default `true`) -- separate statements with semicolons. If
you pass `false` then whenever possible we will use a newline instead of a
semicolon, leading to more readable output of uglified code (size before
gzip could be smaller; size after gzip insignificantly larger).
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
- `width` (default 80) -- only takes effect when beautification is on, this
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
PhantomJS users should set this option to `true`.
- `width` (default `80`) -- only takes effect when beautification is on, this
specifies an (orientative) line width that the beautifier will try to
obey. It refers to the width of the line text (excluding indentation).
It doesn't work very well currently, but it does make the code generated
by UglifyJS more readable.
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
function expressions. See
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
@@ -873,10 +949,6 @@ when this flag is on:
- `new Object()` → `{}`
- `String(exp)` or `exp.toString()` → `"" + exp`
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
- `typeof foo == "undefined"` → `foo === void 0`
- `void 0` → `undefined` (if there is a variable named "undefined" in
scope; we do it because the variable name will be mangled, typically
reduced to a single character)
### Conditional compilation
@@ -993,8 +1065,9 @@ var result = UglifyJS.minify(ast, {
### Working with Uglify AST
Transversal and transformation of the native AST can be performed through
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively.
[`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
respectively.
### ESTree / SpiderMonkey AST
@@ -1026,3 +1099,54 @@ in total it's a bit more than just using UglifyJS's own parser.
[acorn]: https://github.com/ternjs/acorn
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
### Uglify Fast Minify Mode
It's not well known, but whitespace removal and symbol mangling accounts
for 95% of the size reduction in minified code for most JavaScript - not
elaborate code transforms. One can simply disable `compress` to speed up
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
comparable minify speeds and gzip sizes to
[`butternut`](https://www.npmjs.com/package/butternut):
| d3.js | minify size | gzip size | minify time (seconds) |
| --- | ---: | ---: | ---: |
| original | 451,131 | 108,733 | - |
| uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
| uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
| butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
| uglify-js@3.0.24 mangle=true, compress=true | 212,511 | 71,560 | 3.36 |
| babili@0.1.4 | 210,713 | 72,140 | 12.64 |
To enable fast minify mode from the CLI use:
```
uglifyjs file.js -m
```
To enable fast minify mode with the API use:
```js
UglifyJS.minify(code, { compress: false, mangle: true });
```
#### Source maps and debugging
Various `compress` transforms that simplify, rearrange, inline and remove code
are known to have an adverse effect on debugging with source maps. This is
expected as code is optimized and mappings are often simply not possible as
some code no longer exists. For highest fidelity in source map debugging
disable the Uglify `compress` option and just use `mangle`.
### Compiler assumptions
To allow for better optimizations, the compiler makes various assumptions:
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
objects they have not been overridden.
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
- `arguments.callee`, `arguments.caller` and `Function.prototype.caller` are not used.
- The code doesn't expect the contents of `Function.prototype.toString()` or
`Error.prototype.stack` to be anything in particular.
- Getting and setting properties on a plain object does not cause other side effects
(using `.watch()` or `Proxy`).
- Object properties can be added, removed and modified (not prevented with
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
`Object.preventExtensions()` or `Object.seal()`).

View File

@@ -1,24 +1,5 @@
environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4.0"
- nodejs_version: "6.0"
build: off
matrix:
fast_finish: true
platform:
- x86
- x64
install:
- ps: Install-Product node $env:nodejs_version $env:platform
- npm install
test_script:
- node --version
- npm --version
- npm test
build: off
- echo No longer in use

View File

@@ -3,11 +3,7 @@
"use strict";
// workaround for tty output truncation upon process.exit()
[process.stdout, process.stderr].forEach(function(stream){
if (stream._handle && stream._handle.setBlocking)
stream._handle.setBlocking(true);
});
require("../tools/exit");
var fs = require("fs");
var info = require("../package.json");
@@ -15,7 +11,7 @@ var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
var files = {};
var options = {
compress: false,
@@ -35,34 +31,45 @@ else if (process.argv.indexOf("options") >= 0) program.helpInformation = functio
}
return text.join("\n");
};
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js("mangle-props", true));
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js("beautify", true));
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
program.option("-c, --compress [options]", "Enable compressor/specify compressor 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("-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("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file.");
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("--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("--rename", "Force symbol expansion.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.")
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("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages.");
program.option("--warn", "Print warning messages.");
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);
if (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") {
fatal("ERROR: cannot write source map to STDOUT");
fatal("cannot write source map to STDOUT");
}
[
"compress",
"enclose",
"ie8",
"mangle",
"sourceMap",
@@ -73,12 +80,25 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
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) {
options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) {
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 (typeof options.output != "object") options.output = {};
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
@@ -100,7 +120,7 @@ if (program.mangleProps) {
if (typeof program.mangleProps != "object") program.mangleProps = {};
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
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 = {};
@@ -119,9 +139,14 @@ if (program.parse) {
if (!program.parse.acorn && !program.parse.spidermonkey) {
options.parse = program.parse;
} 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")) {
options.rename = true;
} else if (!program.rename) {
options.rename = false;
}
var convert_path = function(name) {
return name;
};
@@ -134,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.args.length) {
print_error("WARN: Ignoring input files since --self was passed");
}
if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name);
@@ -170,9 +188,11 @@ function convert_ast(fn) {
}
function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
print_error("WARN: " + msg);
};
var content = program.sourceMap && program.sourceMap.content;
if (content && content != "inline") {
UglifyJS.AST_Node.info("Using input source map: " + content);
options.sourceMap.content = read_file(content, content);
}
if (program.timings) options.timings = true;
try {
if (program.parse) {
@@ -196,35 +216,58 @@ function run() {
} catch (ex) {
fatal(ex);
}
var result = UglifyJS.minify(files, options);
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);
}
if (result.error) {
var ex = result.error;
if (ex.name == "SyntaxError") {
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
var col = ex.col;
var lines = files[ex.filename].split(/\r?\n/);
var line = lines[ex.line - 1];
if (!line && !col) {
line = lines[ex.line - 2];
col = line.length;
}
if (line) {
var limit = 70;
if (col > limit) {
line = line.slice(col - limit);
col = limit;
var file = files[ex.filename];
if (file) {
var col = ex.col;
var lines = file.split(/\r?\n/);
var line = lines[ex.line - 1];
if (!line && !col) {
line = lines[ex.line - 2];
col = line.length;
}
if (line) {
var limit = 70;
if (col > limit) {
line = line.slice(col - limit);
col = limit;
}
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
}
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
}
}
if (ex.defs) {
} else if (ex.defs) {
print_error("Supported options:");
print_error(format_object(ex.defs));
}
fatal(ex);
} else if (program.output == "ast") {
if (!options.compress && !options.mangle) {
result.ast.figure_out_scope({});
}
print(JSON.stringify(result.ast, function(key, value) {
if (value) switch (key) {
case "thedef":
return symdef(value);
case "enclosed":
return value.length ? value.map(symdef) : undefined;
case "variables":
case "functions":
case "globals":
return value.size() ? value.map(symdef) : undefined;
}
if (skip_key(key)) return;
if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return;
@@ -265,7 +308,11 @@ function run() {
}
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);
process.exit(1);
}
@@ -310,25 +357,17 @@ function read_file(path, default_value) {
}
}
function parse_js(flag, constants) {
function parse_js(flag) {
return function(value, options) {
options = options || {};
try {
UglifyJS.minify(value, {
parse: {
expression: true
},
compress: false,
mangle: false,
output: {
ast: true,
code: false
}
}).ast.walk(new UglifyJS.TreeWalker(function(node) {
UglifyJS.parse(value, {
expression: true
}).walk(new UglifyJS.TreeWalker(function(node) {
if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string();
var value = node.right;
if (!constants) {
if (flag) {
options[name] = value;
} else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string);
@@ -345,35 +384,32 @@ function parse_js(flag, constants) {
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
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
});
}
}));
} catch(ex) {
options[value] = null;
} catch (ex) {
if (flag) {
fatal("cannot parse arguments for '" + flag + "': " + value);
} else {
options[value] = null;
}
}
return options;
}
}
function parse_source_map() {
var parse = parse_js("sourceMap", true);
return function(value, options) {
var hasContent = options && "content" in options;
var settings = parse(value, options);
if (!hasContent && settings.content && settings.content != "inline") {
print_error("INFO: Using input source map: " + settings.content);
settings.content = read_file(settings.content, settings.content);
}
return settings;
}
}
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
}
function symdef(def) {
var ret = (1e6 + def.id) + " " + def.name;
if (def.mangled_name) ret += " " + def.mangled_name;
return ret;
}
function format_object(obj) {
var lines = [];
var padding = "";

View File

@@ -44,21 +44,21 @@
"use strict";
function DEFNODE(type, props, methods, base) {
if (arguments.length < 4) base = AST_Node;
if (!props) props = [];
else props = props.split(/\s+/);
if (typeof base === "undefined") base = AST_Node;
props = props ? props.split(/\s+/) : [];
var self_props = props;
if (base && base.PROPS)
props = props.concat(base.PROPS);
var code = "return function AST_" + type + "(props){ if (props) { ";
for (var i = props.length; --i >= 0;) {
code += "this." + props[i] + " = props." + props[i] + ";";
}
if (base && base.PROPS) props = props.concat(base.PROPS);
var code = [
"return function AST_", type, "(props){",
"if(props){",
];
props.forEach(function(prop) {
code.push("this.", prop, "=props.", prop, ";");
});
var proto = base && new base;
if (proto && proto.initialize || (methods && methods.initialize))
code += "this.initialize();";
code += "}}";
var ctor = new Function(code)();
if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();");
code.push("}}");
var ctor = new Function(code.join(""))();
if (proto) {
ctor.prototype = proto;
ctor.BASE = base;
@@ -71,11 +71,11 @@ function DEFNODE(type, props, methods, base) {
if (type) {
ctor.prototype.TYPE = ctor.TYPE = type;
}
if (methods) for (i in methods) if (HOP(methods, i)) {
if (/^\$/.test(i)) {
ctor[i.substr(1)] = methods[i];
if (methods) for (var name in methods) if (HOP(methods, name)) {
if (/^\$/.test(name)) {
ctor[name.substr(1)] = methods[name];
} else {
ctor.prototype[i] = methods[i];
ctor.prototype[name] = methods[name];
}
}
ctor.DEFMETHOD = function(name, method) {
@@ -85,9 +85,9 @@ function DEFNODE(type, props, methods, base) {
exports["AST_" + type] = ctor;
}
return ctor;
};
}
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", {
}, null);
var AST_Node = DEFNODE("Node", "start end", {
@@ -118,11 +118,25 @@ var AST_Node = DEFNODE("Node", "start end", {
}
}, null);
AST_Node.warn_function = null;
AST_Node.warn = function(txt, props) {
if (AST_Node.warn_function)
AST_Node.warn_function(string_template(txt, props));
};
(AST_Node.log_function = function(fn, verbose) {
var printed = Object.create(null);
if (fn) {
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 ]----- */
@@ -134,11 +148,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value scope quote", {
var AST_Directive = DEFNODE("Directive", "value quote", {
$documentation: "Represents a directive, like \"use strict\";",
$propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character"
},
}, AST_Statement);
@@ -149,29 +162,25 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.body._walk(visitor);
});
}
}, AST_Statement);
function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Statement) {
body._walk(visitor);
}
else for (var i = 0, len = body.length; i < len; i++) {
body[i]._walk(visitor);
}
};
node.body.forEach(function(node) {
node._walk(visitor);
});
}
var AST_Block = DEFNODE("Block", "body", {
$documentation: "A body of statements (usually bracketed)",
$documentation: "A body of statements (usually braced)",
$propdoc: {
body: "[AST_Statement*] an array of statements"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
walk_body(this, visitor);
});
}
@@ -198,7 +207,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
label: "[AST_Label] a label definition"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.label._walk(visitor);
this.body._walk(visitor);
});
@@ -209,8 +218,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
var label = node.label;
var def = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === def) {
if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
node.label.thedef = label;
label.references.push(node);
}
@@ -234,7 +242,7 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
var AST_Do = DEFNODE("Do", null, {
$documentation: "A `do` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.body._walk(visitor);
this.condition._walk(visitor);
});
@@ -244,7 +252,7 @@ var AST_Do = DEFNODE("Do", null, {
var AST_While = DEFNODE("While", null, {
$documentation: "A `while` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
});
@@ -259,7 +267,7 @@ var AST_For = DEFNODE("For", "init condition step", {
step: "[AST_Node?] the `for` update clause, or null if empty"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
if (this.init) this.init._walk(visitor);
if (this.condition) this.condition._walk(visitor);
if (this.step) this.step._walk(visitor);
@@ -268,15 +276,14 @@ var AST_For = DEFNODE("For", "init condition step", {
}
}, AST_IterationStatement);
var AST_ForIn = DEFNODE("ForIn", "init name object", {
var AST_ForIn = DEFNODE("ForIn", "init object", {
$documentation: "A `for ... in` statement",
$propdoc: {
init: "[AST_Node] the `for/in` initialization code",
name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
object: "[AST_Node] the object that we're looping through"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.init._walk(visitor);
this.object._walk(visitor);
this.body._walk(visitor);
@@ -290,7 +297,7 @@ var AST_With = DEFNODE("With", "expression", {
expression: "[AST_Node] the `with` expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.body._walk(visitor);
});
@@ -299,10 +306,9 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
@@ -311,6 +317,16 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
},
clone: function(deep) {
var node = this._clone(deep);
if (this.variables) node.variables = this.variables.clone();
if (this.functions) node.functions = this.functions.clone();
if (this.enclosed) node.enclosed = this.enclosed.slice();
return node;
},
pinned: function() {
return this.uses_eval || this.uses_with;
}
}, AST_Block);
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
@@ -318,20 +334,46 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$propdoc: {
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
},
wrap_commonjs: function(name) {
wrap: function(name) {
var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
return parse([
"(function(exports){'$ORIG';})(typeof ",
name,
"=='undefined'?(",
name,
"={}):",
name,
");"
].join(""), {
filename: "wrap=" + JSON.stringify(name)
}).transform(new TreeTransformer(function(node) {
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);
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",
$propdoc: {
name: "[AST_SymbolDeclaration?] the name of this function",
@@ -339,12 +381,11 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
if (this.name) this.name._walk(visitor);
var argnames = this.argnames;
for (var i = 0, len = argnames.length; i < len; i++) {
argnames[i]._walk(visitor);
}
this.argnames.forEach(function(argname) {
argname._walk(visitor);
});
walk_body(this, visitor);
});
}
@@ -354,11 +395,11 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda);
var AST_Function = DEFNODE("Function", null, {
var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
var AST_Defun = DEFNODE("Defun", "inlined", {
$documentation: "A function definition"
}, AST_Lambda);
@@ -374,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"
},
_walk: function(visitor) {
return visitor._visit(this, this.value && function(){
return visitor._visit(this, this.value && function() {
this.value._walk(visitor);
});
}
@@ -394,7 +435,7 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
label: "[AST_LabelRef?] the label, or null if none",
},
_walk: function(visitor) {
return visitor._visit(this, this.label && function(){
return visitor._visit(this, this.label && function() {
this.label._walk(visitor);
});
}
@@ -417,7 +458,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
alternative: "[AST_Statement?] the `else` part, or null if not present"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
if (this.alternative) this.alternative._walk(visitor);
@@ -433,7 +474,7 @@ var AST_Switch = DEFNODE("Switch", "expression", {
expression: "[AST_Node] the `switch` “discriminant”"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -454,7 +495,7 @@ var AST_Case = DEFNODE("Case", "expression", {
expression: "[AST_Node] the `case` expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -470,7 +511,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
bfinally: "[AST_Finally?] the finally block, or null if not present"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
walk_body(this, visitor);
if (this.bcatch) this.bcatch._walk(visitor);
if (this.bfinally) this.bfinally._walk(visitor);
@@ -484,7 +525,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
argname: "[AST_SymbolCatch] symbol for the exception"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.argname._walk(visitor);
walk_body(this, visitor);
});
@@ -503,11 +544,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
definitions: "[AST_VarDef*] array of variable definitions"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var definitions = this.definitions;
for (var i = 0, len = definitions.length; i < len; i++) {
definitions[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.definitions.forEach(function(defn) {
defn._walk(visitor);
});
});
}
}, AST_Statement);
@@ -523,7 +563,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.name._walk(visitor);
if (this.value) this.value._walk(visitor);
});
@@ -539,12 +579,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
args: "[AST_Node*] array of arguments"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.args.forEach(function(node) {
node._walk(visitor);
});
});
}
});
@@ -559,7 +598,7 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
expressions: "[AST_Node*] array of expressions (at least two)"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expressions.forEach(function(node) {
node._walk(visitor);
});
@@ -572,13 +611,25 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
$propdoc: {
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"
},
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, {
$documentation: "A dotted property access expression",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -587,7 +638,7 @@ var AST_Dot = DEFNODE("Dot", null, {
var AST_Sub = DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.property._walk(visitor);
});
@@ -601,7 +652,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
expression: "[AST_Node] expression that this unary operator applies to"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -623,7 +674,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
right: "[AST_Node] right-hand side expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.left._walk(visitor);
this.right._walk(visitor);
});
@@ -638,7 +689,7 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
alternative: "[AST_Node]"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.consequent._walk(visitor);
this.alternative._walk(visitor);
@@ -658,11 +709,10 @@ var AST_Array = DEFNODE("Array", "elements", {
elements: "[AST_Node*] array of elements"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var elements = this.elements;
for (var i = 0, len = elements.length; i < len; i++) {
elements[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.elements.forEach(function(element) {
element._walk(visitor);
});
});
}
});
@@ -673,11 +723,10 @@ var AST_Object = DEFNODE("Object", "properties", {
properties: "[AST_ObjectProperty*] array of properties"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var properties = this.properties;
for (var i = 0, len = properties.length; i < len; i++) {
properties[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.properties.forEach(function(prop) {
prop._walk(visitor);
});
});
}
});
@@ -685,11 +734,11 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.",
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.value._walk(visitor);
});
}
@@ -758,7 +807,7 @@ var AST_Label = DEFNODE("Label", "references", {
}
}, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", null, {
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
$documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol);
@@ -772,9 +821,6 @@ var AST_This = DEFNODE("This", null, {
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
getValue: function() {
return this.value;
}
});
var AST_String = DEFNODE("String", "value quote", {
@@ -785,11 +831,10 @@ var AST_String = DEFNODE("String", "value quote", {
}
}, AST_Constant);
var AST_Number = DEFNODE("Number", "value literal", {
var AST_Number = DEFNODE("Number", "value", {
$documentation: "A number literal",
$propdoc: {
value: "[number] the numeric value",
literal: "[string] numeric value as string (optional)"
}
}, AST_Constant);
@@ -816,12 +861,12 @@ var AST_NaN = DEFNODE("NaN", null, {
var AST_Undefined = DEFNODE("Undefined", null, {
$documentation: "The `undefined` value",
value: (function(){}())
value: function(){}()
}, AST_Atom);
var AST_Hole = DEFNODE("Hole", null, {
$documentation: "A hole in an array",
value: (function(){}())
value: function(){}()
}, AST_Atom);
var AST_Infinity = DEFNODE("Infinity", null, {
@@ -849,17 +894,17 @@ function TreeWalker(callback) {
this.visit = callback;
this.stack = [];
this.directives = Object.create(null);
};
}
TreeWalker.prototype = {
_visit: function(node, descend) {
this.push(node);
var ret = this.visit(node, descend ? function(){
var ret = this.visit(node, descend ? function() {
descend.call(node);
} : noop);
if (!ret && descend) {
descend.call(node);
}
this.pop(node);
this.pop();
return ret;
},
parent: function(n) {
@@ -873,9 +918,8 @@ TreeWalker.prototype = {
}
this.stack.push(node);
},
pop: function(node) {
this.stack.pop();
if (node instanceof AST_Lambda) {
pop: function() {
if (this.stack.pop() instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives);
}
},
@@ -901,24 +945,6 @@ TreeWalker.prototype = {
}
}
},
in_boolean_context: function() {
var stack = this.stack;
var i = stack.length, self = stack[--i];
while (i > 0) {
var p = stack[--i];
if ((p instanceof AST_If && p.condition === self) ||
(p instanceof AST_Conditional && p.condition === self) ||
(p instanceof AST_DWLoop && p.condition === self) ||
(p instanceof AST_For && p.condition === self) ||
(p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
{
return true;
}
if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
return false;
self = p;
}
},
loopcontrol_target: function(node) {
var stack = this.stack;
if (node.label) for (var i = stack.length; --i >= 0;) {
@@ -931,5 +957,36 @@ TreeWalker.prototype = {
|| node instanceof AST_Break && x instanceof AST_Switch)
return x;
}
},
in_boolean_context: function() {
var self = this.self();
for (var i = 0, p; p = this.parent(i); i++) {
if (p instanceof AST_Conditional && p.condition === self
|| p instanceof AST_DWLoop && p.condition === self
|| p instanceof AST_For && 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) {
return true;
}
if (p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")
|| p instanceof AST_Conditional
|| p.tail_node() === self) {
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 {
return false;
}
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,47 @@
"use strict";
var to_ascii = typeof atob == "undefined" ? function(b64) {
return new Buffer(b64, "base64").toString();
} : atob;
var to_base64 = typeof btoa == "undefined" ? function(str) {
return new Buffer(str).toString("base64");
} : btoa;
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();
};
to_base64 = function(str) {
return new Buffer(str).toString("base64");
};
} 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(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
AST_Node.warn("inline source map not found");
return null;
function read_source_map(name, toplevel) {
var comments = toplevel.end.comments_after;
for (var i = comments.length; --i >= 0;) {
var comment = comments[i];
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]);
}
}
AST_Node.warn("inline source map not found: " + name);
}
function parse_source_map(content) {
try {
return JSON.parse(content);
} catch (ex) {
throw new Error("invalid input source map: " + content);
}
return to_ascii(match[2]);
}
function set_shorthand(name, options, keys) {
@@ -29,7 +57,6 @@ function set_shorthand(name, options, keys) {
function init_cache(cache) {
if (!cache) return;
if (!("cname" in cache)) cache.cname = -1;
if (!("props" in cache)) {
cache.props = new Dictionary();
} else if (!(cache.props instanceof Dictionary)) {
@@ -39,22 +66,22 @@ function init_cache(cache) {
function to_json(cache) {
return {
cname: cache.cname,
props: cache.props.toObject()
};
}
function minify(files, options) {
var warn_function = AST_Node.warn_function;
try {
options = defaults(options, {
compress: {},
enclose: false,
ie8: false,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
rename: undefined,
sourceMap: false,
timings: false,
toplevel: false,
@@ -64,10 +91,13 @@ function minify(files, options) {
var timings = options.timings && {
start: Date.now()
};
if (options.rename === undefined) {
options.rename = options.compress && options.mangle;
}
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
@@ -78,11 +108,16 @@ function minify(files, options) {
reserved: [],
toplevel: false,
}, true);
if (options.nameCache && options.mangle.properties) {
if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
options.mangle.properties = {};
}
if (!("cache" in options.mangle.properties)) {
if (options.mangle.properties.keep_quoted) {
quoted_props = options.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
options.mangle.properties.reserved = quoted_props;
}
if (options.nameCache && !("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {};
}
}
@@ -99,13 +134,11 @@ function minify(files, options) {
}, true);
}
var warnings = [];
if (options.warnings && !AST_Node.warn_function) {
AST_Node.warn_function = function(warning) {
warnings.push(warning);
};
}
if (options.warnings) AST_Node.log_function(function(warning) {
warnings.push(warning);
}, options.warnings == "verbose");
if (timings) timings.parse = Date.now();
var toplevel;
var source_maps, toplevel;
if (files instanceof AST_Toplevel) {
toplevel = files;
} else {
@@ -114,29 +147,47 @@ function minify(files, options) {
}
options.parse = options.parse || {};
options.parse.toplevel = null;
var source_map_content = options.sourceMap && options.sourceMap.content;
if (typeof source_map_content == "string" && source_map_content != "inline") {
source_map_content = parse_source_map(source_map_content);
}
source_maps = source_map_content && Object.create(null);
for (var name in files) if (HOP(files, name)) {
options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse);
if (options.sourceMap && options.sourceMap.content == "inline") {
if (Object.keys(files).length > 1)
throw new Error("inline source map only works with singular input");
options.sourceMap.content = read_source_map(files[name]);
options.parse.toplevel = toplevel = parse(files[name], options.parse);
if (source_maps) {
if (source_map_content == "inline") {
var inlined_content = read_source_map(name, toplevel);
if (inlined_content) {
source_maps[name] = parse_source_map(inlined_content);
}
} else {
source_maps[name] = source_map_content;
}
}
}
toplevel = options.parse.toplevel;
}
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
[ "enclose", "wrap" ].forEach(function(action) {
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 (options.rename) {
toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle);
}
if (timings) timings.scope1 = Date.now();
if (options.compress) toplevel.figure_out_scope(options.mangle);
if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope2 = Date.now();
if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
base54.reset();
toplevel.compute_char_frequency(options.mangle);
toplevel.mangle_names(options.mangle);
}
@@ -151,19 +202,17 @@ function minify(files, options) {
}
if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) {
if (typeof options.sourceMap.content == "string") {
options.sourceMap.content = JSON.parse(options.sourceMap.content);
}
options.output.source_map = SourceMap({
content: options.sourceMap.includeSources,
file: options.sourceMap.filename,
orig: options.sourceMap.content,
orig: source_maps,
root: options.sourceMap.root
});
if (options.sourceMap.includeSources) {
if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable");
} 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]);
}
}
}
@@ -174,10 +223,14 @@ function minify(files, options) {
result.code = stream.get();
if (options.sourceMap) {
result.map = options.output.source_map.toString();
if (options.sourceMap.url == "inline") {
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map);
} else if (options.sourceMap.url) {
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url;
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);
} else {
result.code += "\n//# sourceMappingURL=" + url;
}
}
}
}
@@ -190,14 +243,15 @@ function minify(files, options) {
if (timings) {
timings.end = Date.now();
result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2),
compress: 1e-3 * (timings.scope2 - timings.compress),
parse: 1e-3 * (timings.rename - timings.parse),
rename: 1e-3 * (timings.compress - timings.rename),
compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),
total: 1e-3 * (timings.end - timings.start)
}
};
}
if (warnings.length) {
result.warnings = warnings;
@@ -205,7 +259,5 @@ function minify(files, options) {
return result;
} catch (ex) {
return { error: ex };
} finally {
AST_Node.warn_function = warn_function;
}
}

View File

@@ -43,11 +43,9 @@
"use strict";
(function(){
var normalize_directives = function(body) {
(function() {
function normalize_directives(body) {
var in_directive = true;
for (var i = 0; i < body.length; i++) {
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
body[i] = new AST_Directive({
@@ -59,9 +57,8 @@
in_directive = false;
}
}
return body;
};
}
var MOZ_TO_ME = {
Program: function(M) {
@@ -129,7 +126,7 @@
return new AST_Array({
start : my_start_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);
})
});
@@ -138,7 +135,7 @@
return new AST_Object({
start : my_start_token(M),
end : my_end_token(M),
properties : M.properties.map(function(prop){
properties : M.properties.map(function(prop) {
prop.type = "Property";
return from_moz(prop)
})
@@ -180,6 +177,17 @@
end : my_end_token(M)
};
if (val === null) return new AST_Null(args);
var rx = M.regex;
if (rx && rx.pattern) {
// RegExpLiteral as per ESTree AST spec
args.value = new RegExp(rx.pattern, rx.flags);
args.value.raw_source = rx.pattern;
return new AST_RegExp(args);
} else if (rx) {
// support legacy RegExp
args.value = M.regex && M.raw ? M.raw : val;
return new AST_RegExp(args);
}
switch (typeof val) {
case "string":
args.value = val;
@@ -189,16 +197,6 @@
return new AST_Number(args);
case "boolean":
return new (val ? AST_True : AST_False)(args);
default:
var rx = M.regex;
if (rx && rx.pattern) {
// RegExpLiteral as per ESTree AST spec
args.value = new RegExp(rx.pattern, rx.flags).toString();
} else {
// support legacy RegExp
args.value = M.regex && M.raw ? M.raw : val;
}
return new AST_RegExp(args);
}
},
Identifier: function(M) {
@@ -405,19 +403,20 @@
var def = M.definition();
return {
type: "Identifier",
name: def ? def.mangled_name || def.name : M.name
name: def && def.mangled_name || M.name
};
});
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
var value = M.value;
var flags = M.value.toString().match(/[gimuy]*$/)[0];
var value = "/" + M.value.raw_source + "/" + flags;
return {
type: "Literal",
value: value,
raw: value.toString(),
raw: value,
regex: {
pattern: value.source,
flags: value.toString().match(/[gimuy]*$/)[0]
pattern: M.value.raw_source,
flags: flags
}
};
});
@@ -478,7 +477,7 @@
endpos : range ? range[0] : moznode.start,
raw : raw_token(moznode),
});
};
}
function my_end_token(moznode) {
var loc = moznode.loc, end = loc && loc.end;
@@ -493,7 +492,7 @@
endpos : range ? range[1] : moznode.end,
raw : raw_token(moznode),
});
};
}
function map(moztype, mytype, propmap) {
var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
@@ -505,7 +504,7 @@
me_to_moz += "return {\n" +
"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);
if (!m) throw new Error("Can't understand property map: " + prop);
var moz = m[1], how = m[2], my = m[3];
@@ -548,7 +547,7 @@
);
MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz);
};
}
var FROM_MOZ_STACK = null;
@@ -557,13 +556,28 @@
var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
FROM_MOZ_STACK.pop();
return ret;
};
}
AST_Node.from_mozilla_ast = function(node){
AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK;
FROM_MOZ_STACK = [];
var ast = from_moz(node);
FROM_MOZ_STACK = save_stack;
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_LabelRef) {
for (var level = 0, parent; parent = this.parent(level); level++) {
if (parent instanceof AST_Scope) break;
if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
node.thedef = parent.label;
break;
}
}
if (!node.thedef) {
var s = node.start;
js_error("Undefined label " + node.name, s.file, s.line, s.col, s.pos);
}
}
}));
return ast;
};
@@ -583,24 +597,24 @@
}
}
return moznode;
};
}
function def_to_moz(mytype, handler) {
mytype.DEFMETHOD("to_mozilla_ast", function() {
return set_moz_loc(this, handler(this));
});
};
}
function to_moz(node) {
return node != null ? node.to_mozilla_ast() : null;
};
}
function to_moz_block(node) {
return {
type: "BlockStatement",
body: node.body.map(to_moz)
};
};
}
function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
@@ -611,5 +625,5 @@
type: type,
body: body
};
};
}
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -53,20 +53,57 @@ function find_builtins(reserved) {
"-Infinity",
"undefined",
].forEach(add);
[ Object, Array, Function, Number,
String, Boolean, Error, Math,
Date, RegExp
].forEach(function(ctor){
[
Array,
Boolean,
Date,
Error,
Function,
Math,
Number,
Object,
RegExp,
String,
].forEach(function(ctor) {
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
Object.getOwnPropertyNames(ctor.prototype).map(add);
}
});
function add(name) {
push_uniq(reserved, name);
}
}
function reserve_quoted_keys(ast, reserved) {
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
}));
function add(name) {
push_uniq(reserved, name);
}
}
function addStrings(node, add) {
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) {
addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) {
add(node.value);
} else if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
}
return true;
}));
}
function mangle_properties(ast, options) {
options = defaults(options, {
builtins: false,
@@ -76,82 +113,67 @@ function mangle_properties(ast, options) {
only_cache: false,
regex: null,
reserved: null,
});
}, true);
var reserved = options.reserved;
if (!Array.isArray(reserved)) reserved = [];
if (!options.builtins) find_builtins(reserved);
var cache = options.cache;
if (cache == null) {
cache = {
cname: -1,
props: new Dictionary()
};
var cname = -1;
var cache;
if (options.cache) {
cache = options.cache.props;
cache.each(function(mangled_name) {
push_uniq(reserved, mangled_name);
});
} else {
cache = new Dictionary();
}
var regex = options.regex;
var keep_quoted = options.keep_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
// the same as passing an empty string.
var debug = options.debug !== false;
var debug_name_suffix;
if (debug) {
debug_name_suffix = (options.debug === true ? "" : options.debug);
}
var debug_suffix;
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
var names_to_mangle = [];
var unmangleable = [];
var to_keep = {};
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal) {
add(node.key, keep_quoted && node.quote);
}
else if (node instanceof AST_ObjectProperty) {
add(node.key);
} else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above
add(node.key.name);
}
else if (node instanceof AST_Dot) {
} else if (node instanceof AST_Dot) {
add(node.property);
}
else if (node instanceof AST_Sub) {
addStrings(node.property, keep_quoted);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
} else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
addStrings(node.args[1], add);
}
}));
// 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 (!(keep_quoted && node.quote))
node.key = mangle(node.key);
}
else if (node instanceof AST_ObjectProperty) {
node.key = mangle(node.key);
} else if (node instanceof AST_ObjectProperty) {
// setter or getter
node.key.name = mangle(node.key.name);
}
else if (node instanceof AST_Dot) {
} else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
} else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property);
} else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
node.args[1] = mangleStrings(node.args[1]);
}
else if (node instanceof AST_Sub) {
if (!keep_quoted)
node.property = mangleStrings(node.property);
}
// else if (node instanceof AST_String) {
// if (should_mangle(node.value)) {
// AST_Node.warn(
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
// file : node.start.file,
// line : node.start.line,
// col : node.start.col,
// prop : node.value
// }
// );
// }
// }
}));
// only function declarations after this line
@@ -159,102 +181,50 @@ function mangle_properties(ast, options) {
function can_mangle(name) {
if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) {
return cache.props.has(name);
}
if (options.only_cache) return cache.has(name);
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true;
}
function should_mangle(name) {
if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0;
return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
}
function add(name, keep) {
if (keep) {
to_keep[name] = true;
return;
}
if (can_mangle(name))
push_uniq(names_to_mangle, name);
if (!should_mangle(name)) {
push_uniq(unmangleable, name);
}
function add(name) {
if (can_mangle(name)) push_uniq(names_to_mangle, name);
if (!should_mangle(name)) push_uniq(unmangleable, name);
}
function mangle(name) {
if (!should_mangle(name)) {
return name;
}
var mangled = cache.props.get(name);
var mangled = cache.get(name);
if (!mangled) {
if (debug) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
mangled = debug_mangled;
}
var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
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
if (!mangled) {
// Note: `can_mangle()` does not check if the name collides with the `to_keep` set
// (filled with quoted properties when `keep_quoted` is set). Make sure we add this
// check so we don't collide with a quoted name.
do {
mangled = base54(++cache.cname);
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
}
cache.props.set(name, mangled);
if (!mangled) do {
mangled = base54(++cname);
} while (!can_mangle(mangled));
cache.set(name, mangled);
}
return mangled;
}
function addStrings(node, keep) {
var out = {};
try {
(function walk(node){
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Sequence) {
walk(node.expressions[node.expressions.length - 1]);
return true;
}
if (node instanceof AST_String) {
add(node.value, keep);
return true;
}
if (node instanceof AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){
return node.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]);
}
else if (node instanceof AST_String) {
} else if (node instanceof AST_String) {
node.value = mangle(node.value);
}
else if (node instanceof AST_Conditional) {
} else if (node instanceof AST_Conditional) {
node.consequent = mangleStrings(node.consequent);
node.alternative = mangleStrings(node.alternative);
}

View File

@@ -43,46 +43,43 @@
"use strict";
function SymbolDef(scope, index, orig) {
function SymbolDef(scope, orig, init) {
this.name = orig.name;
this.orig = [ orig ];
this.init = init;
this.eliminated = 0;
this.scope = scope;
this.references = [];
this.replaced = 0;
this.global = false;
this.mangled_name = null;
this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++;
};
this.lambda = orig instanceof AST_SymbolLambda;
}
SymbolDef.next_id = 1;
SymbolDef.prototype = {
unmangleable: function(options) {
if (!options) options = {};
return (this.global && !options.toplevel)
return this.global && !options.toplevel
|| this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|| (options.keep_fnames
|| !options.eval && this.scope.pinned()
|| options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun));
|| this.orig[0] instanceof AST_SymbolDefun);
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
if (this.global && cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name);
}
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
var sym = this.orig[0];
if (options.ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
} else if (!this.mangled_name && !this.unmangleable(options)) {
var def;
if (def = this.redefined()) {
this.mangled_name = def.mangled_name || def.name;
} else
this.mangled_name = s.next_mangled(options, this);
} else {
this.mangled_name = next_mangled_name(this.scope, options, this);
}
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
@@ -93,7 +90,7 @@ SymbolDef.prototype = {
}
};
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
options = defaults(options, {
cache: null,
ie8: false,
@@ -102,9 +99,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// pass 1: setup scope chaining and handle definitions
var self = this;
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var tw = new TreeWalker(function(node, descend){
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
@@ -117,28 +113,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
labels = new Dictionary();
descend();
scope = save_scope;
defun = save_defun;
labels = save_labels;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_LabeledStatement) {
var l = node.label;
if (labels.has(l.name)) {
throw new Error(string_template("Label {name} defined twice", l));
}
labels.set(l.name, l);
descend();
labels.del(l.name);
return true; // no descend again
return true;
}
if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope)
s.uses_with = true;
for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
return;
}
if (node instanceof AST_Symbol) {
@@ -148,109 +130,122 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.thedef = node;
node.references = [];
}
if (node instanceof AST_SymbolLambda) {
defun.def_function(node);
}
else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is
// the parent scope. The reason is that we enter a new
// scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit
// later.
(node.scope = defun.parent_scope).def_function(node);
}
else if (node instanceof AST_SymbolVar) {
defun.def_variable(node);
if (node instanceof AST_SymbolDefun) {
// This should be defined in the parent scope, as we encounter the
// AST_Defun node before getting to its AST_Symbol.
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
} else if (node instanceof AST_SymbolLambda) {
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
if (options.ie8) def.defun = defun.parent_scope.resolve();
} else if (node instanceof AST_SymbolVar) {
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
node.reference(options);
}
node.reference(options);
}
}
else if (node instanceof AST_SymbolCatch) {
} else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
name: node.name,
line: node.start.line,
col: node.start.col
}));
node.thedef = sym;
}
});
self.walk(tw);
// pass 2: find back references and eval
self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
var tw = new TreeWalker(function(node) {
if (node instanceof AST_LoopControl) {
if (node.label) node.label.thedef.references.push(node);
return true;
}
if (node instanceof AST_SymbolRef) {
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);
if (!sym) {
sym = self.def_global(node);
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
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.reference(options);
return true;
}
// ensure mangling works if catch reuses a scope variable
var def;
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
var s = node.scope;
while (s) {
if (node instanceof AST_SymbolCatch) {
var def = node.definition().redefined();
if (def) for (var s = node.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (s === def.scope) break;
s = s.parent_scope;
}
return true;
}
});
self.walk(tw);
// pass 3: fix up any scoping issue with IE8
if (options.ie8) {
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) {
var name = node.name;
var refs = node.thedef.references;
var scope = node.thedef.defun;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
refs.forEach(function(ref) {
ref.thedef = def;
ref.reference(options);
});
node.thedef = def;
return true;
if (options.ie8) self.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolCatch) {
var scope = node.thedef.defun;
if (scope.name instanceof AST_SymbolLambda && scope.name.name == node.name) {
scope = scope.parent_scope.resolve();
}
}));
}
redefine(node, scope);
return true;
}
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;
}
}));
if (options.cache) {
this.cname = options.cache.cname;
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;
if (globals.has(name)) {
return globals.get(name);
} else {
var g = new SymbolDef(this, globals.size(), node);
var g = new SymbolDef(this, node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
@@ -258,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.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
@@ -268,7 +263,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
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);
this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({
@@ -280,8 +275,7 @@ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
var s = this.scope;
while (s) {
for (var s = this.scope; s; s = s.parent_scope) {
push_uniq(s.enclosed, def);
if (options.keep_fnames) {
s.functions.each(function(d) {
@@ -289,7 +283,6 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
});
}
if (s === def.scope) break;
s = s.parent_scope;
}
});
@@ -298,69 +291,89 @@ AST_Symbol.DEFMETHOD("reference", function(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;
return this.variables.get(name)
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
AST_Scope.DEFMETHOD("def_function", function(symbol){
this.functions.set(symbol.name, this.def_variable(symbol));
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
var def = this.def_variable(symbol, init);
if (!def.init || def.init instanceof AST_Defun) def.init = init;
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol);
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
if (def.init instanceof AST_Function) def.init = init;
} else {
def = new SymbolDef(this, symbol, init);
this.variables.set(symbol.name, def);
def.global = !this.parent_scope;
} else {
def = this.variables.get(symbol.name);
def.orig.push(symbol);
}
return symbol.thedef = def;
});
AST_Scope.DEFMETHOD("next_mangled", function(options){
var ext = this.enclosed;
out: while (true) {
var m = base54(++this.cname);
if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling.
if (options.reserved.indexOf(m) >= 0) continue;
// we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in
// inner scopes.
for (var i = ext.length; --i >= 0;) {
var sym = ext[i];
var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
if (m == name) continue out;
}
return m;
}
AST_Lambda.DEFMETHOD("resolve", return_this);
AST_Scope.DEFMETHOD("resolve", function() {
return this.parent_scope.resolve();
});
AST_Toplevel.DEFMETHOD("resolve", return_this);
AST_Function.DEFMETHOD("next_mangled", function(options, def){
// #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
var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
// the function's mangled_name is null when keep_fnames is true
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
function names_in_use(scope, options) {
var names = scope.names_in_use;
if (!names) {
scope.names_in_use = names = Object.create(scope.mangled_names || null);
scope.cname_holes = [];
var cache = options.cache && options.cache.props;
scope.enclosed.forEach(function(def) {
if (def.unmangleable(options)) names[def.name] = true;
if (def.global && cache && cache.has(def.name)) {
names[cache.get(def.name)] = true;
}
});
}
return names;
}
function next_mangled_name(scope, options, def) {
var in_use = names_in_use(scope, options);
var holes = scope.cname_holes;
var names = Object.create(null);
var scopes = [ scope ];
def.references.forEach(function(sym) {
var scope = sym.scope;
do {
if (scopes.indexOf(scope) < 0) {
for (var name in names_in_use(scope, options)) {
names[name] = true;
}
scopes.push(scope);
} else break;
} while (scope = scope.parent_scope);
});
var name;
for (var i = 0; i < holes.length; i++) {
name = base54(holes[i]);
if (names[name]) continue;
holes.splice(i, 1);
scope.names_in_use[name] = true;
return name;
}
while (true) {
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
if (!tricky_name || tricky_name != name)
return name;
name = base54(++scope.cname);
if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names[name]) break;
holes.push(scope.cname);
}
});
scope.names_in_use[name] = true;
return name;
}
AST_Symbol.DEFMETHOD("unmangleable", function(options){
AST_Symbol.DEFMETHOD("unmangleable", function(options) {
var def = this.definition();
return !def || def.unmangleable(options);
});
@@ -368,28 +381,19 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
// labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function(){
return this.definition().references.length == 0
&& !(this.scope.uses_eval || this.scope.uses_with);
AST_Symbol.DEFMETHOD("unreferenced", function() {
return !this.definition().references.length && !this.scope.pinned();
});
AST_Symbol.DEFMETHOD("undeclared", function(){
return this.definition().undeclared;
});
AST_LabelRef.DEFMETHOD("undeclared", return_false);
AST_Label.DEFMETHOD("undeclared", return_false);
AST_Symbol.DEFMETHOD("definition", function(){
AST_Symbol.DEFMETHOD("definition", function() {
return this.thedef;
});
AST_Symbol.DEFMETHOD("global", function(){
AST_Symbol.DEFMETHOD("global", function() {
return this.definition().global;
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
function _default_mangler_options(options) {
options = defaults(options, {
eval : false,
ie8 : false,
@@ -398,69 +402,159 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
toplevel : false,
});
if (!Array.isArray(options.reserved)) options.reserved = [];
return options;
});
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options);
// Never mangle arguments
options.reserved.push('arguments');
push_uniq(options.reserved, "arguments");
options.reserved.has = makePredicate(options.reserved);
return options;
}
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
options = _default_mangler_options(options);
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of
// the AST_SymbolDeclaration that it points to).
var lname = -1;
var to_mangle = [];
if (options.cache) {
this.globals.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
if (options.cache && options.cache.props) {
var mangled_names = this.mangled_names = Object.create(null);
options.cache.props.each(function(mangled_name) {
mangled_names[mangled_name] = true;
});
}
var tw = new TreeWalker(function(node, descend){
var redefined = [];
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label
var save_nesting = lname;
descend();
lname = save_nesting;
return true; // don't descend again in TreeWalker
return true;
}
if (node instanceof AST_Scope) {
var p = tw.parent(), a = [];
node.variables.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
a.push(symbol);
}
descend();
if (options.cache && node instanceof AST_Toplevel) {
node.globals.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);
});
to_mangle.push.apply(to_mangle, a);
return;
return true;
}
if (node instanceof AST_Label) {
var name;
do name = base54(++lname); while (!is_identifier(name));
do {
name = base54(++lname);
} while (RESERVED_WORDS[name]);
node.mangled_name = name;
return true;
}
if (!options.ie8 && node instanceof AST_SymbolCatch) {
to_mangle.push(node.definition());
return;
if (!options.ie8 && node instanceof AST_Catch) {
var def = node.argname.definition();
var redef = defer_redef(def, node.argname);
descend();
if (!redef) mangle(def);
return true;
}
});
this.walk(tw);
to_mangle.forEach(function(def){ def.mangle(options) });
redefined.forEach(mangle);
if (options.cache) {
options.cache.cname = this.cname;
function mangle(def) {
if (options.reserved.has[def.name]) return;
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("compute_char_frequency", function(options){
options = this._default_mangler_options(options);
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
var cache = options.cache && options.cache.props;
var avoid = Object.create(null);
options.reserved.forEach(to_avoid);
this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
}));
return avoid;
function to_avoid(name) {
avoid[name] = true;
}
function add_def(def) {
var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
to_avoid(name);
}
});
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
base54.reset();
base54.sort();
options = _default_mangler_options(options);
var avoid = this.find_colliding_names(options);
var cname = 0;
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
}));
function next_name() {
var name;
do {
name = base54(cname++);
} while (avoid[name] || RESERVED_WORDS[name]);
return name;
}
function rename(def) {
if (def.global && options.cache) return;
if (def.unmangleable(options)) return;
if (options.reserved.has[def.name]) return;
var redef = def.redefined();
var name = redef ? redef.rename || redef.name : next_name();
def.rename = name;
def.orig.forEach(function(sym) {
sym.name = name;
});
def.references.forEach(function(sym) {
sym.name = name;
});
}
});
AST_Node.DEFMETHOD("tail_node", return_this);
AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
options = _default_mangler_options(options);
base54.reset();
try {
AST_Node.prototype.print = function(stream, force_parens) {
this._print(stream, force_parens);
@@ -487,23 +581,27 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
skip_string(node.consequent);
skip_string(node.alternative);
} else if (node instanceof AST_Sequence) {
skip_string(node.expressions[node.expressions.length - 1]);
skip_string(node.tail_node());
}
}
});
var base54 = (function() {
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
var digits = "0123456789".split("");
var freq = Object.create(null);
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;
function reset() {
frequency = Object.create(null);
leading.forEach(function(ch) {
frequency[ch] = 0;
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
frequency = Object.create(freq);
}
base54.consider = function(str, delta) {
for (var i = str.length; --i >= 0;) {
@@ -514,7 +612,7 @@ var base54 = (function() {
return frequency[b] - frequency[a];
}
base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
chars = leading.sort(compare).concat(digits.sort(compare));
};
base54.reset = reset;
reset();
@@ -528,6 +626,6 @@ var base54 = (function() {
base = 64;
} while (num > 0);
return ret;
};
}
return base54;
})();

View File

@@ -43,55 +43,144 @@
"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) {
options = defaults(options, {
file : null,
root : null,
orig : null,
orig_line_diff : 0,
dest_line_diff : 0,
});
var generator = new MOZ_SourceMap.SourceMapGenerator({
file : options.file,
sourceRoot : options.root
});
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
if (orig_map && Array.isArray(options.orig.sources)) {
orig_map._sources.toArray().forEach(function(source) {
var sourceContent = orig_map.sourceContentFor(source, true);
if (sourceContent) {
generator.setSourceContent(source, sourceContent);
}
content: false,
file: null,
root: null,
orig: null,
}, true);
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 ];
map.mappings = map.mappings.split(/;/).map(function(line) {
indices[0] = 0;
return line.split(/,/).map(function(segment) {
return indices.slice(0, vlq_decode(indices, segment));
});
});
}
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 generated_line = 1;
var generated_column = 0;
var source_index = 0;
var original_line = 1;
var original_column = 0;
var name_index = 0;
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,
});
}
};
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
if (orig_map) {
var info = orig_map.originalPositionFor({
line: orig_line,
column: orig_col
});
if (info.source === null) {
return;
}
source = info.source;
orig_line = info.line;
orig_col = info.column;
name = info.name || name;
if (generated_line < gen_line) {
generated_column = 0;
do {
mappings += ";";
} while (++generated_line < gen_line);
} else if (mappings) {
mappings += ",";
}
generator.addMapping({
generated : { line: gen_line + options.dest_line_diff, column: gen_col },
original : { line: orig_line + options.orig_line_diff, column: orig_col },
source : source,
name : name
});
};
return {
add : add,
get : function() { return generator },
toString : function() { return JSON.stringify(generator.toJSON()); }
};
};
mappings += vlq_encode(gen_col - generated_column);
generated_column = gen_col;
var src_idx = sources.index(source);
mappings += vlq_encode(src_idx - source_index);
source_index = src_idx;
mappings += vlq_encode(orig_line - original_line);
original_line = orig_line;
mappings += vlq_encode(orig_col - original_column);
original_column = orig_col;
if (name != null) {
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";
// Tree transformer helpers.
function TreeTransformer(before, after) {
TreeWalker.call(this);
this.before = before;
@@ -52,166 +50,136 @@ function TreeTransformer(before, after) {
}
TreeTransformer.prototype = new TreeWalker;
(function(undefined){
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) {
if (!tw.after) {
x = this;
descend(x, tw);
} else {
tw.stack[tw.stack.length - 1] = x = this;
descend(x, tw);
y = tw.after(x, in_list);
if (y !== undefined) x = y;
}
}
tw.pop(this);
return x;
});
};
(function(DEF) {
function do_list(list, tw) {
return MAP(list, function(node){
return List(list, function(node) {
return node.transform(tw, true);
});
};
}
_(AST_Node, noop);
_(AST_LabeledStatement, function(self, tw){
DEF(AST_Node, noop);
DEF(AST_LabeledStatement, function(self, tw) {
self.label = self.label.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_SimpleStatement, function(self, tw){
DEF(AST_SimpleStatement, function(self, tw) {
self.body = self.body.transform(tw);
});
_(AST_Block, function(self, tw){
DEF(AST_Block, function(self, tw) {
self.body = do_list(self.body, tw);
});
_(AST_DWLoop, function(self, tw){
DEF(AST_Do, function(self, tw) {
self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw);
});
DEF(AST_While, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_For, function(self, tw){
DEF(AST_For, function(self, tw) {
if (self.init) self.init = self.init.transform(tw);
if (self.condition) self.condition = self.condition.transform(tw);
if (self.step) self.step = self.step.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_ForIn, function(self, tw){
DEF(AST_ForIn, function(self, tw) {
self.init = self.init.transform(tw);
self.object = self.object.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_With, function(self, tw){
DEF(AST_With, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_Exit, function(self, tw){
DEF(AST_Exit, function(self, tw) {
if (self.value) self.value = self.value.transform(tw);
});
_(AST_LoopControl, function(self, tw){
DEF(AST_LoopControl, function(self, tw) {
if (self.label) self.label = self.label.transform(tw);
});
_(AST_If, function(self, tw){
DEF(AST_If, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
if (self.alternative) self.alternative = self.alternative.transform(tw);
});
_(AST_Switch, function(self, tw){
DEF(AST_Switch, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Case, function(self, tw){
DEF(AST_Case, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Try, function(self, tw){
DEF(AST_Try, function(self, tw) {
self.body = do_list(self.body, tw);
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
});
_(AST_Catch, function(self, tw){
DEF(AST_Catch, function(self, tw) {
self.argname = self.argname.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Definitions, function(self, tw){
DEF(AST_Definitions, function(self, tw) {
self.definitions = do_list(self.definitions, tw);
});
_(AST_VarDef, function(self, tw){
DEF(AST_VarDef, function(self, tw) {
self.name = self.name.transform(tw);
if (self.value) self.value = self.value.transform(tw);
});
_(AST_Lambda, function(self, tw){
DEF(AST_Lambda, function(self, tw) {
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);
self.body = do_list(self.body, tw);
});
_(AST_Call, function(self, tw){
DEF(AST_Call, function(self, tw) {
self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw);
});
_(AST_Sequence, function(self, tw){
DEF(AST_Sequence, function(self, tw) {
self.expressions = do_list(self.expressions, tw);
});
_(AST_Dot, function(self, tw){
DEF(AST_Dot, function(self, tw) {
self.expression = self.expression.transform(tw);
});
_(AST_Sub, function(self, tw){
DEF(AST_Sub, function(self, tw) {
self.expression = self.expression.transform(tw);
self.property = self.property.transform(tw);
});
_(AST_Unary, function(self, tw){
DEF(AST_Unary, function(self, tw) {
self.expression = self.expression.transform(tw);
});
_(AST_Binary, function(self, tw){
DEF(AST_Binary, function(self, tw) {
self.left = self.left.transform(tw);
self.right = self.right.transform(tw);
});
_(AST_Conditional, function(self, tw){
DEF(AST_Conditional, function(self, tw) {
self.condition = self.condition.transform(tw);
self.consequent = self.consequent.transform(tw);
self.alternative = self.alternative.transform(tw);
});
_(AST_Array, function(self, tw){
DEF(AST_Array, function(self, tw) {
self.elements = do_list(self.elements, tw);
});
_(AST_Object, function(self, tw){
DEF(AST_Object, function(self, tw) {
self.properties = do_list(self.properties, tw);
});
_(AST_ObjectProperty, function(self, tw){
DEF(AST_ObjectProperty, function(self, 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

@@ -43,33 +43,25 @@
"use strict";
function slice(a, start) {
return Array.prototype.slice.call(a, start || 0);
};
function characters(str) {
return str.split("");
};
}
function member(name, array) {
return array.indexOf(name) >= 0;
};
}
function find_if(func, array) {
for (var i = 0, n = array.length; i < n; ++i) {
if (func(array[i]))
return array[i];
}
};
for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i];
}
function repeat_string(str, i) {
if (i <= 0) return "";
if (i == 1) return str;
var d = repeat_string(str, i >> 1);
d += d;
if (i & 1) d += str;
return d;
};
return i & 1 ? d + str : d;
}
function configure_error_stack(fn) {
Object.defineProperty(fn.prototype, "stack", {
@@ -78,7 +70,7 @@ function configure_error_stack(fn) {
err.name = this.name;
try {
throw err;
} catch(e) {
} catch (e) {
return e.stack;
}
}
@@ -88,27 +80,23 @@ function configure_error_stack(fn) {
function DefaultsError(msg, defs) {
this.message = msg;
this.defs = defs;
};
}
DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError);
DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs);
};
function defaults(args, defs, croak) {
if (args === true)
args = {};
if (args === true) args = {};
var ret = args || {};
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i))
DefaultsError.croak("`" + i + "` is not a supported option", defs);
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
throw new DefaultsError("`" + i + "` is not a supported option", defs);
}
for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
}
return ret;
};
}
function merge(obj, ext) {
var count = 0;
@@ -117,7 +105,7 @@ function merge(obj, ext) {
count++;
}
return count;
};
}
function noop() {}
function return_false() { return false; }
@@ -125,8 +113,8 @@ function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
var MAP = (function(){
function MAP(a, f, backwards) {
var List = (function() {
function List(a, f, backwards) {
var ret = [], top = [], i;
function doit() {
var val = f(a[i], i);
@@ -139,8 +127,7 @@ var MAP = (function(){
} else {
top.push(val);
}
}
else if (val !== skip) {
} else if (val !== skip) {
if (val instanceof Splice) {
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
} else {
@@ -148,8 +135,8 @@ var MAP = (function(){
}
}
return is_last;
};
if (a instanceof Array) {
}
if (Array.isArray(a)) {
if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break;
ret.reverse();
@@ -157,132 +144,56 @@ var MAP = (function(){
} else {
for (i = 0; i < a.length; ++i) if (doit()) break;
}
}
else {
} else {
for (i in a) if (HOP(a, i)) if (doit()) break;
}
return top.concat(ret);
};
MAP.at_top = function(val) { return new AtTop(val) };
MAP.splice = function(val) { return new Splice(val) };
MAP.last = function(val) { return new Last(val) };
var skip = MAP.skip = {};
function AtTop(val) { this.v = val };
function Splice(val) { this.v = val };
function Last(val) { this.v = val };
return MAP;
}
List.at_top = function(val) { return new AtTop(val); };
List.splice = function(val) { return new Splice(val); };
List.last = function(val) { return new Last(val); };
var skip = List.skip = {};
function AtTop(val) { this.v = val; }
function Splice(val) { this.v = val; }
function Last(val) { this.v = val; }
return List;
})();
function push_uniq(array, el) {
if (array.indexOf(el) < 0)
array.push(el);
};
if (array.indexOf(el) < 0) return array.push(el);
}
function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){
return text.replace(/\{(.+?)\}/g, function(str, p) {
return props && props[p];
});
};
}
function remove(array, el) {
for (var i = array.length; --i >= 0;) {
if (array[i] === el) array.splice(i, 1);
}
};
var index = array.indexOf(el);
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 set_difference(a, b) {
return a.filter(function(el){
return b.indexOf(el) < 0;
});
};
function set_intersection(a, b) {
return a.filter(function(el){
return b.indexOf(el) >= 0;
});
};
// this function is taken from Acorn [1], written by Marijn Haverbeke
// [1] https://github.com/marijnh/acorn
function makePredicate(words) {
if (!(words instanceof Array)) words = words.split(" ");
var f = "", cats = [];
out: for (var i = 0; i < words.length; ++i) {
for (var j = 0; j < cats.length; ++j)
if (cats[j][0].length == words[i].length) {
cats[j].push(words[i]);
continue out;
}
cats.push([words[i]]);
}
function quote(word) {
return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
switch (s) {
case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029";
}
return s;
});
}
function compareTo(arr) {
if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
f += "switch(str){";
for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
f += "return true}return false;";
}
// When there are more than three length categories, an outer
// switch first dispatches on the lengths, to save on comparisons.
if (cats.length > 3) {
cats.sort(function(a, b) {return b.length - a.length;});
f += "switch(str.length){";
for (var i = 0; i < cats.length; ++i) {
var cat = cats[i];
f += "case " + cat[0].length + ":";
compareTo(cat);
}
f += "}";
// Otherwise, simply generate a flat `switch` statement.
} else {
compareTo(words);
}
return new Function("str", f);
};
if (!Array.isArray(words)) words = words.split(" ");
var map = Object.create(null);
words.forEach(function(word) {
map[word] = true;
});
return map;
}
function all(array, predicate) {
for (var i = array.length; --i >= 0;)
if (!predicate(array[i]))
if (!predicate(array[i], i))
return false;
return true;
};
}
function Dictionary() {
this._values = Object.create(null);
this._size = 0;
};
}
Dictionary.prototype = {
set: function(key, val) {
if (!this.has(key)) ++this._size;
@@ -306,6 +217,12 @@ Dictionary.prototype = {
return this;
},
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) {
for (var i in this._values)
f(this._values[i], i.substr(1));
@@ -319,6 +236,13 @@ Dictionary.prototype = {
ret.push(f(this._values[i], i.substr(1)));
return ret;
},
clone: function() {
var ret = new Dictionary();
for (var i in this._values)
ret._values[i] = this._values[i];
ret._size = this._size;
return ret;
},
toObject: function() { return this._values }
};
Dictionary.fromObject = function(obj) {
@@ -336,20 +260,22 @@ function HOP(obj, prop) {
// a statement.
function first_in_statement(stack) {
var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||
(p instanceof AST_Binary && p.left === node ) ||
(p instanceof AST_UnaryPostfix && p.expression === node ))
{
node = p;
} else {
return false;
for (var i = 0, p; p = stack.parent(i++); node = p) {
if (p.TYPE == "Call") {
if (p.expression === node) continue;
} else if (p instanceof AST_Binary) {
if (p.left === node) continue;
} else if (p instanceof AST_Conditional) {
if (p.condition === node) continue;
} else if (p instanceof AST_PropAccess) {
if (p.expression === node) continue;
} else if (p instanceof AST_Sequence) {
if (p.expressions[0] === node) continue;
} else if (p instanceof AST_Statement) {
return p.body === node;
} else if (p instanceof AST_UnaryPostfix) {
if (p.expression === node) continue;
}
return false;
}
}

View File

@@ -1,23 +1,17 @@
{
"name": "uglify-js",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.0.23",
"version": "3.9.0",
"engines": {
"node": ">=0.8.0"
},
"maintainers": [
"Alex Lam <alexlamsl@gmail.com>",
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
],
"repository": {
"type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git"
},
"bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues"
},
"repository": "mishoo/UglifyJS2",
"main": "tools/node.js",
"bin": {
"uglifyjs": "bin/uglifyjs"
@@ -29,16 +23,37 @@
"LICENSE"
],
"dependencies": {
"commander": "~2.9.0",
"source-map": "~0.5.1"
"commander": "~2.20.3"
},
"devDependencies": {
"acorn": "~5.0.3",
"mocha": "~2.3.4",
"semver": "~5.3.0"
"acorn": "~7.1.0",
"semver": "~6.3.0"
},
"scripts": {
"test": "node test/run-tests.js"
"test": "node test/compress.js && node test/mocha.js"
},
"keywords": ["uglify", "uglify-js", "minify", "minifier", "es5"]
"keywords": [
"cli",
"compress",
"compressor",
"ecma",
"ecmascript",
"es",
"es5",
"javascript",
"js",
"jsmin",
"min",
"minification",
"minifier",
"minify",
"optimize",
"optimizer",
"pack",
"packer",
"parse",
"parser",
"uglifier",
"uglify"
]
}

View File

@@ -6,26 +6,29 @@
var createHash = require("crypto").createHash;
var fetch = require("./fetch");
var fork = require("child_process").fork;
var zlib = require("zlib");
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc");
}
args.push("--timings");
var urls = [
"https://code.jquery.com/jquery-3.2.1.js",
"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js",
"https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://code.jquery.com/jquery-3.4.1.js",
"https://code.angularjs.org/1.7.8/angular.js",
"https://unpkg.com/mathjs@6.2.3/dist/math.js",
"https://unpkg.com/react@15.3.2/dist/react.js",
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js",
"https://raw.githubusercontent.com/kangax/html-minifier/v4.0.0/dist/htmlminifier.js",
];
var results = {};
var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
var failures = [];
var sum = { input: 0, output: 0, gzip: 0 };
urls.forEach(function(url) {
var info = results[url];
console.log();
@@ -33,10 +36,14 @@ function done() {
console.log(info.log);
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("GZipped: ", info.gzip, "bytes");
console.log("SHA1 sum:", info.sha1);
if (info.code) {
failures.push(url);
}
sum.input += info.input;
sum.output += info.output;
sum.gzip += info.gzip;
});
if (failures.length) {
console.error("Benchmark failed:");
@@ -44,6 +51,13 @@ function done() {
console.error(url);
});
process.exit(1);
} else {
console.log();
console.log("Subtotal");
console.log();
console.log("Original:", sum.input, "bytes");
console.log("Uglified:", sum.output, "bytes");
console.log("GZipped: ", sum.gzip, "bytes");
}
}
}
@@ -51,6 +65,7 @@ urls.forEach(function(url) {
results[url] = {
input: 0,
output: 0,
gzip: 0,
log: ""
};
fetch(url, function(err, res) {
@@ -61,6 +76,10 @@ urls.forEach(function(url) {
}).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length;
}).pipe(zlib.createGzip({
level: zlib.Z_BEST_COMPRESSION
})).on("data", function(data) {
results[url].gzip += data.length;
}).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex");
done();

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;
}

778
test/compress/arguments.js Normal file
View File

@@ -0,0 +1,778 @@
replace_index: {
options = {
arguments: true,
evaluate: true,
properties: true,
}
input: {
var arguments = [];
console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
var arguments = [];
console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
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: {
options = {
arguments: true,
evaluate: true,
keep_fargs: false,
properties: true,
}
input: {
var arguments = [];
console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
var arguments = [];
console.log(arguments[0]);
(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);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
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: {
options = {
arguments: true,
}
input: {
(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: {
(function(a, b) {
var c = a;
var d = b;
var a = "foo";
b++;
a = "moo";
b *= 2;
console.log(a, b, c, d, a, b);
})("bar", 42);
}
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: {
options = {
unsafe : true,
evaluate : true
};
evaluate: true,
strings: true,
unsafe: true,
}
input: {
var a = [ "foo", "bar", "baz" ].join("");
var a1 = [ "foo", "bar", "baz" ].join();
@@ -64,9 +65,10 @@ constant_join: {
constant_join_2: {
options = {
unsafe : true,
evaluate : true
};
evaluate: true,
strings: true,
unsafe: true,
}
input: {
var a = [ "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: {
options = {
unsafe: true,
evaluate: true,
};
strings: true,
unsafe: true,
}
input: {
var foo, bar, baz;
var a = [ null ].join();
var b = [ , ].join();
var c = [ , 1, , 3 ].join();
@@ -111,6 +115,7 @@ constant_join_3: {
var l = [ foo, bar + "baz" ].join("");
}
expect: {
var foo, bar, baz;
var a = "";
var b = "";
var c = ",1,,3";
@@ -128,50 +133,224 @@ constant_join_3: {
for_loop: {
options = {
unsafe : true,
unused : true,
evaluate : true,
reduce_vars : true
};
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
unused: true,
}
input: {
function f0() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}
var b = 0;
for (var i = 0; i < a.length; i++)
b += a[i];
return b;
}
function f1() {
var a = [1, 2, 3];
for (var i = 0, len = a.length; i < len; i++) {
console.log(a[i]);
}
var b = 0;
for (var i = 0, len = a.length; i < len; i++)
b += a[i];
return b;
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) {
a[i]++;
}
}
}
expect: {
function f0() {
var a = [1, 2, 3];
for (var i = 0; i < 3; i++)
console.log(a[i]);
}
function f1() {
var a = [1, 2, 3];
for (var i = 0; i < 3; i++)
console.log(a[i]);
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++)
a[i]++;
return a[2];
}
console.log(f0(), f1(), f2());
}
expect: {
function f0() {
var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++)
b += a[i];
return b;
}
function f1() {
var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++)
b += a[i];
return b;
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++)
a[i]++;
return a[2];
}
console.log(f0(), f1(), f2());
}
expect_stdout: "6 6 4"
}
index: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a[1]);
}
expect: {
console.log(1, 2);
}
expect_stdout: "1 2"
}
length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a.length);
}
expect: {
console.log(2);
}
expect_stdout: "2"
}
index_length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a.length);
}
expect: {
console.log(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

@@ -13,7 +13,7 @@ ascii_only_true: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
}
}
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
}
ascii_only_false: {
@@ -31,5 +31,5 @@ ascii_only_false: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
}
}
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
}

View File

@@ -1,25 +1,25 @@
asm_mixed: {
options = {
sequences : true,
properties : true,
dead_code : true,
drop_debugger : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
loops : true,
unused : true,
hoist_funs : true,
keep_fargs : true,
keep_fnames : false,
hoist_vars : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
negate_iife : true
};
assignments: true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
drop_debugger: true,
evaluate: true,
hoist_funs: true,
hoist_vars: true,
if_return: true,
join_vars: true,
keep_fargs: true,
keep_fnames: false,
loops: true,
negate_iife: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
// adapted from http://asmjs.org/spec/latest/
function asm_GeometricMean(stdlib, foreign, buffer) {
@@ -96,7 +96,7 @@ asm_mixed: {
return +sum;
}
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);
return { geometricMean: geometricMean };
@@ -104,3 +104,131 @@ asm_mixed: {
}
}
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.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: {
options = {
assignments: true,
evaluate: true,
}
input: {
@@ -60,6 +61,7 @@ op_equals_left_local_var: {
op_equals_right_local_var: {
options = {
assignments: true,
evaluate: true,
}
input: {
@@ -123,6 +125,7 @@ op_equals_right_local_var: {
}
op_equals_left_global_var: {
options = {
assignments: true,
evaluate: true,
}
input: {
@@ -179,6 +182,7 @@ op_equals_left_global_var: {
op_equals_right_global_var: {
options = {
assignments: true,
evaluate: true,
}
input: {
@@ -236,3 +240,170 @@ op_equals_right_global_var: {
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

@@ -1,76 +0,0 @@
keep_comparisons: {
options = {
comparisons: true,
unsafe_comps: false
}
input: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
expect: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
}
keep_comparisons_with_unsafe_comps: {
options = {
comparisons: true,
unsafe_comps: true
}
input: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
expect: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj2 >= obj1;
var result2 = obj2 > obj1;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
}
dont_change_in_or_instanceof_expressions: {
input: {
1 in 1;
null in null;
1 instanceof 1;
null instanceof null;
}
expect: {
1 in 1;
null in null;
1 instanceof 1;
null instanceof null;
}
}

View File

@@ -0,0 +1,442 @@
comparisons: {
options = {
comparisons: true,
}
input: {
var obj1, obj2;
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
expect: {
var obj1, obj2;
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj2 <= obj1;
var result4 = obj2 < obj1;
}
}
unsafe_comps: {
options = {
comparisons: true,
conditionals: true,
unsafe_comps: true,
}
input: {
var obj1, obj2;
obj1 <= obj2 ? f1() : g1();
obj1 < obj2 ? f2() : g2();
obj1 >= obj2 ? f3() : g3();
obj1 > obj2 ? f4() : g4();
}
expect: {
var obj1, obj2;
(obj2 < obj1 ? g1 : f1)();
(obj1 < obj2 ? f2 : g2)();
(obj1 < obj2 ? g3 : f3)();
(obj2 < obj1 ? f4 : g4)();
}
}
dont_change_in_or_instanceof_expressions: {
input: {
1 in 1;
null in null;
1 instanceof 1;
null instanceof null;
}
expect: {
1 in 1;
null in null;
1 instanceof 1;
null instanceof null;
}
}
self_comparison_1: {
options = {
comparisons: true,
}
input: {
a === a;
a !== b;
b.c === a.c;
b.c !== b.c;
}
expect: {
a == a;
a !== b;
b.c === a.c;
b.c != b.c;
}
}
self_comparison_2: {
options = {
comparisons: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {}
var o = {};
console.log(f != f, o === o);
}
expect: {
function f() {}
var o = {};
console.log(false, true);
}
expect_stdout: "false true"
}
issue_2857_1: {
options = {
comparisons: true,
}
input: {
function f1(a) {
a === undefined || a === null;
a === undefined || a !== null;
a !== undefined || a === null;
a !== undefined || a !== null;
a === undefined && a === null;
a === undefined && a !== null;
a !== undefined && a === null;
a !== undefined && a !== null;
}
function f2(a) {
a === null || a === undefined;
a === null || a !== undefined;
a !== null || a === undefined;
a !== null || a !== undefined;
a === null && a === undefined;
a === null && a !== undefined;
a !== null && a === undefined;
a !== null && a !== undefined;
}
}
expect: {
function f1(a) {
null == a;
void 0 === a || null !== a;
void 0 !== a || null === a;
void 0 !== a || null !== a;
void 0 === a && null === a;
void 0 === a && null !== a;
void 0 !== a && null === a;
null != a;
}
function f2(a) {
null == a;
null === a || void 0 !== a;
null !== a || void 0 === a;
null !== a || void 0 !== a;
null === a && void 0 === a;
null === a && void 0 !== a;
null !== a && void 0 === a;
null != a;
}
}
}
issue_2857_2: {
options = {
comparisons: true,
}
input: {
function f(a, p) {
a === undefined || a === null || p;
a === undefined || a !== null || p;
a !== undefined || a === null || p;
a !== undefined || a !== null || p;
a === undefined && a === null || p;
a === undefined && a !== null || p;
a !== undefined && a === null || p;
a !== undefined && a !== null || p;
}
}
expect: {
function f(a, p) {
null == a || p;
void 0 === a || null !== a || p;
void 0 !== a || null === a || p;
void 0 !== a || null !== a || p;
void 0 === a && null === a || p;
void 0 === a && null !== a || p;
void 0 !== a && null === a || p;
null != a || p;
}
}
}
issue_2857_3: {
options = {
comparisons: true,
}
input: {
function f(a, p) {
a === undefined || a === null && p;
a === undefined || a !== null && p;
a !== undefined || a === null && p;
a !== undefined || a !== null && p;
a === undefined && a === null && p;
a === undefined && a !== null && p;
a !== undefined && a === null && p;
a !== undefined && a !== null && p;
}
}
expect: {
function f(a, p) {
void 0 === a || null === a && p;
void 0 === a || null !== a && p;
void 0 !== a || null === a && p;
void 0 !== a || null !== a && p;
void 0 === a && null === a && p;
void 0 === a && null !== a && p;
void 0 !== a && null === a && p;
null != a && p;
}
}
}
issue_2857_4: {
options = {
comparisons: true,
}
input: {
function f(a, p) {
p || a === undefined || a === null;
p || a === undefined || a !== null;
p || a !== undefined || a === null;
p || a !== undefined || a !== null;
p || a === undefined && a === null;
p || a === undefined && a !== null;
p || a !== undefined && a === null;
p || a !== undefined && a !== null;
}
}
expect: {
function f(a, p) {
p || null == a;
p || void 0 === a || null !== a;
p || void 0 !== a || null === a;
p || void 0 !== a || null !== a;
p || void 0 === a && null === a;
p || void 0 === a && null !== a;
p || void 0 !== a && null === a;
p || null != a;
}
}
}
issue_2857_5: {
options = {
comparisons: true,
}
input: {
function f(a, p) {
p && a === undefined || a === null;
p && a === undefined || a !== null;
p && a !== undefined || a === null;
p && a !== undefined || a !== null;
p && a === undefined && a === null;
p && a === undefined && a !== null;
p && a !== undefined && a === null;
p && a !== undefined && a !== null;
}
}
expect: {
function f(a, p) {
p && void 0 === a || null === a;
p && void 0 === a || null !== a;
p && void 0 !== a || null === a;
p && void 0 !== a || null !== a;
p && void 0 === a && null === a;
p && void 0 === a && null !== a;
p && void 0 !== a && null === a;
p && null != a;
}
}
}
issue_2857_6: {
options = {
comparisons: true,
pure_getters: "strict",
reduce_vars: true,
}
input: {
function f(a) {
if (({}).b === undefined || {}.b === null)
return a.b !== undefined && a.b !== null;
}
console.log(f({
a: [ null ],
get b() {
return this.a.shift();
}
}));
}
expect: {
function f(a) {
if (null == {}.b)
return void 0 !== a.b && null !== a.b;
}
console.log(f({
a: [ null ],
get b() {
return this.a.shift();
}
}));
}
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: {
options = {
evaluate: true
};
evaluate: true,
}
input: {
var a = "foo" + "bar" + x() + "moo" + "foo" + y() + "x" + "y" + "z" + q();
var b = "foo" + 1 + x() + 2 + "boo";
@@ -21,12 +21,14 @@ concat_1: {
var c = 1 + x() + 2 + "boo";
var d = 1 + x() + 2 + 3 + "boo";
var e = 1 + x() + 2 + "X3boo";
var f = "\x00360\08\0";
var f = "\x00360\x008\0";
}
}
concat_2: {
options = {};
options = {
strings: true,
}
input: {
console.log(
1 + (2 + 3),
@@ -55,7 +57,9 @@ concat_2: {
}
concat_3: {
options = {};
options = {
strings: true,
}
input: {
console.log(
1 + 2 + (3 + 4 + 5),
@@ -84,7 +88,9 @@ concat_3: {
}
concat_4: {
options = {};
options = {
strings: true,
}
input: {
console.log(
1 + "2" + (3 + 4 + 5),
@@ -113,7 +119,9 @@ concat_4: {
}
concat_5: {
options = {};
options = {
strings: true,
}
input: {
console.log(
"1" + 2 + (3 + 4 + 5),
@@ -142,7 +150,9 @@ concat_5: {
}
concat_6: {
options = {};
options = {
strings: true,
}
input: {
console.log(
"1" + "2" + (3 + 4 + 5),
@@ -171,6 +181,9 @@ concat_6: {
}
concat_7: {
options = {
strings: true,
}
input: {
console.log(
"" + 1,
@@ -197,6 +210,9 @@ concat_7: {
}
concat_8: {
options = {
strings: true,
}
input: {
console.log(
1 + "",
@@ -221,3 +237,20 @@ concat_8: {
}
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: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
if (foo) bar();
if (!foo); else bar();
@@ -18,8 +18,8 @@ ifs_1: {
ifs_2: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
if (foo) {
x();
@@ -41,18 +41,18 @@ ifs_2: {
}
expect: {
foo ? x() : bar ? y() : baz && z();
foo ? x() : bar ? y() : baz ? z() : t();
(foo ? x : bar ? y : baz ? z : t)();
}
}
ifs_3_should_warn: {
options = {
conditionals : true,
dead_code : true,
evaluate : true,
booleans : true,
side_effects : true,
};
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
}
input: {
var x, y;
if (x && !(x + "1") && y) { // 1
@@ -78,8 +78,8 @@ ifs_3_should_warn: {
ifs_4: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
if (foo && bar) {
x(foo)[10].bar.baz = something();
@@ -95,10 +95,10 @@ ifs_4: {
ifs_5: {
options = {
if_return: true,
conditionals: true,
comparisons: true,
};
conditionals: true,
if_return: true,
}
input: {
function f() {
if (foo) return;
@@ -132,9 +132,9 @@ ifs_5: {
ifs_6: {
options = {
comparisons: true,
conditionals: true,
comparisons: true
};
}
input: {
var x, y;
if (!foo && !bar && !baz && !boo) {
@@ -161,52 +161,74 @@ 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: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
var do_something; // if undeclared it's assumed to have side-effects
if (some_condition()) {
do_something(x);
} else {
do_something(y);
}
if (some_condition()) {
side_effects(x);
} else {
side_effects(y);
function foo(do_something, some_condition) {
if (some_condition) {
do_something(x);
} else {
do_something(y);
}
if (some_condition) {
side_effects(x);
} else {
side_effects(y);
}
}
}
expect: {
var do_something;
do_something(some_condition() ? x : y);
some_condition() ? side_effects(x) : side_effects(y);
function foo(do_something, some_condition) {
do_something(some_condition ? x : y);
some_condition ? side_effects(x) : side_effects(y);
}
}
}
cond_2: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
var x, FooBar;
if (some_condition()) {
x = new FooBar(1);
} else {
x = new FooBar(2);
function foo(x, FooBar, some_condition) {
if (some_condition) {
x = new FooBar(1);
} else {
x = new FooBar(2);
}
}
}
expect: {
var x, FooBar;
x = new FooBar(some_condition() ? 1 : 2);
function foo(x, FooBar, some_condition) {
x = new FooBar(some_condition ? 1 : 2);
}
}
}
cond_3: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
var FooBar;
if (some_condition()) {
@@ -223,8 +245,8 @@ cond_3: {
cond_4: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
var do_something;
if (some_condition()) {
@@ -247,8 +269,8 @@ cond_4: {
cond_5: {
options = {
conditionals: true
};
conditionals: true,
}
input: {
if (some_condition()) {
if (some_other_condition()) {
@@ -267,17 +289,56 @@ cond_5: {
}
}
expect: {
some_condition() && some_other_condition() ? do_something() : alternate();
(some_condition() && some_other_condition() ? do_something : alternate)();
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: {
options = {
conditionals: true,
evaluate : true,
evaluate: true,
side_effects: true,
};
}
input: {
var x, y, z, a, b;
// compress these
@@ -328,7 +389,7 @@ cond_7: {
x = 'foo';
x = 'foo';
x = (condition(), 20);
x = z ? 'fuji' : (condition(), 'fuji');
x = (z || condition(), 'fuji');
x = (condition(), 'foobar');
x = y ? a : b;
x = y ? 'foo' : 'fo';
@@ -338,8 +399,8 @@ cond_7: {
cond_7_1: {
options = {
conditionals: true,
evaluate : true
};
evaluate: true,
}
input: {
var x;
// access to global should be assumed to have side effects
@@ -357,10 +418,10 @@ cond_7_1: {
cond_8: {
options = {
booleans: false,
conditionals: true,
evaluate : true,
booleans : false
};
evaluate: true,
}
input: {
var a;
// compress these
@@ -441,10 +502,10 @@ cond_8: {
cond_8b: {
options = {
booleans: true,
conditionals: true,
evaluate : true,
booleans : true
};
evaluate: true,
}
input: {
var a;
// compress these
@@ -524,10 +585,10 @@ cond_8b: {
cond_8c: {
options = {
booleans: false,
conditionals: true,
evaluate : false,
booleans : false
};
evaluate: false,
}
input: {
var a;
// compress these
@@ -605,11 +666,140 @@ cond_8c: {
}
}
cond_9: {
options = {
conditionals: true,
}
input: {
function f(x, y) {
g() ? x(1) : x(2);
x ? (y || x)() : (y || x)();
x ? y(a, b) : y(d, b, c);
x ? y(a, b, c) : y(a, b, c);
x ? y(a, b, c) : y(a, b, f);
x ? y(a, b, c) : y(a, e, c);
x ? y(a, b, c) : y(a, e, f);
x ? y(a, b, c) : y(d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
expect: {
function f(x, y) {
g() ? x(1) : x(2);
x, (y || x)();
x ? y(a, b) : y(d, b, c);
x, y(a, b, c);
y(a, b, x ? c : f);
y(a, x ? b : e, c);
x ? y(a, b, c) : y(a, e, f);
y(x ? a : d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
}
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: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
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: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f1() { return a == b ? true : x; }
@@ -635,9 +825,21 @@ ternary_boolean_consequent: {
ternary_boolean_alternative: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
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: true,
properties: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f1() { return a == b ? x : true; }
@@ -663,10 +865,11 @@ ternary_boolean_alternative: {
trivial_boolean_ternary_expressions : {
options = {
booleans: true,
conditionals: true,
evaluate : true,
booleans : true
};
evaluate: true,
side_effects: true,
}
input: {
f('foo' in m ? true : false);
f('foo' in m ? false : true);
@@ -737,11 +940,11 @@ trivial_boolean_ternary_expressions : {
issue_1154: {
options = {
booleans: true,
conditionals: true,
evaluate : true,
booleans : true,
evaluate: true,
side_effects: true,
};
}
input: {
function f1(x) { return x ? -1 : -1; }
function f2(x) { return x ? +2 : +2; }
@@ -777,7 +980,7 @@ issue_1154: {
no_evaluate: {
options = {
conditionals: true,
evaluate : false,
evaluate: false,
side_effects: true,
}
input: {
@@ -1015,3 +1218,451 @@ delete_conditional_2: {
}
expect_stdout: true
}
issue_2535_1: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
passes: 2,
side_effects: true,
}
input: {
if (true || x()) y();
if (true && x()) y();
if (x() || true) y();
if (x() && true) y();
if (false || x()) y();
if (false && x()) y();
if (x() || false) y();
if (x() && false) y();
}
expect: {
y();
x() && y();
x(), y();
x() && y();
x() && y();
x() && y();
x();
}
}
issue_2535_2: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
side_effects: true,
}
input: {
function x() {}
function y() {
return "foo";
}
console.log((x() || true) || y());
console.log((y() || true) || x());
console.log((x() || true) && y());
console.log((y() || true) && x());
console.log((x() && true) || y());
console.log((y() && true) || x());
console.log((x() && true) && y());
console.log((y() && true) && x());
console.log((x() || false) || y());
console.log((y() || false) || x());
console.log((x() || false) && y());
console.log((y() || false) && x());
console.log((x() && false) || y());
console.log((y() && false) || x());
console.log((x() && false) && y());
console.log((y() && false) && x());
}
expect: {
function x() {}
function y() {
return "foo";
}
console.log(x() || !0);
console.log(y() || !0);
console.log((x(), y()));
console.log((y(), x()));
console.log(!!x() || y());
console.log(!!y() || x());
console.log(x() && y());
console.log(y() && x());
console.log(x() || y());
console.log(y() || x());
console.log(!!x() && y());
console.log(!!y() && x());
console.log((x(), y()));
console.log((y(), x()));
console.log(x() && !1);
console.log(y() && !1);
}
expect_stdout: [
"true",
"foo",
"foo",
"undefined",
"foo",
"true",
"undefined",
"undefined",
"foo",
"foo",
"false",
"undefined",
"foo",
"undefined",
"undefined",
"false",
]
}
issue_2560: {
options = {
conditionals: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function log(x) {
console.log(x);
}
function foo() {
return log;
}
function bar() {
if (x !== (x = foo())) {
x(1);
} else {
x(2);
}
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect: {
function log(x) {
console.log(x);
}
function bar() {
x !== (x = log) ? x(1) : x(2);
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect_stdout: [
"1",
"2",
]
}
hoist_decl: {
options = {
conditionals: true,
join_vars: true,
sequences: true,
}
input: {
if (x()) {
var a;
y();
} else {
z();
var b;
}
}
expect: {
var a, b;
x() ? y() : z();
}
}
to_and_or: {
options = {
conditionals: true,
}
input: {
var values = [
0,
null,
true,
"foo",
false,
-1 / 0,
void 0,
];
values.forEach(function(x) {
values.forEach(function(y) {
values.forEach(function(z) {
console.log(x ? y || z : z);
});
});
});
}
expect: {
var values = [
0,
null,
true,
"foo",
false,
-1 / 0,
void 0,
];
values.forEach(function(x) {
values.forEach(function(y) {
values.forEach(function(z) {
console.log(x && y || z);
});
});
});
}
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: {
options = {
dead_code: true
};
dead_code: true,
}
input: {
function f() {
a();
@@ -25,8 +25,8 @@ dead_code_1: {
dead_code_2_should_warn: {
options = {
dead_code: true
};
dead_code: true,
}
input: {
function f() {
g();
@@ -62,55 +62,15 @@ dead_code_2_should_warn: {
node_version: "<=4"
}
dead_code_2_should_warn_strict: {
options = {
dead_code: true
};
input: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
// completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope.
if (x) {
y();
var x;
function g(){};
// but nested declarations should not be kept.
(function(){
var q;
function y(){};
})();
}
}
f();
}
expect: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
var x;
}
f();
}
expect_stdout: true
node_version: ">=4"
}
dead_code_constant_boolean_should_warn_more: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
side_effects : true,
};
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
loops: true,
side_effects: true,
}
input: {
while (!((foo && bar) || (x + "0"))) {
console.log("unreachable");
@@ -129,55 +89,21 @@ dead_code_constant_boolean_should_warn_more: {
function bar() {}
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
var x = 10, y;
bar();
}
expect_stdout: true
node_version: "<=4"
}
dead_code_constant_boolean_should_warn_more_strict: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
side_effects : true,
};
input: {
"use strict";
while (!((foo && bar) || (x + "0"))) {
console.log("unreachable");
var foo;
function bar() {}
}
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
asdf();
foo();
var moo;
}
bar();
}
expect: {
"use strict";
var foo;
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
bar();
}
expect_stdout: true
node_version: ">=4"
}
try_catch_finally: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
passes: 2,
side_effects: true,
}
input: {
var a = 1;
@@ -215,18 +141,754 @@ try_catch_finally: {
]
}
accessor: {
collapse_vars_assignment: {
options = {
side_effects: true,
collapse_vars: true,
dead_code: true,
passes: 2,
unused: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
function f0(c) {
var a = 3 / c;
return a = a;
}
}
expect: {
function f0(c) {
return 3 / c;
}
}
expect: {}
}
collapse_vars_lvalues_drop_assign: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f0(x) { var i = ++x; return x += i; }
function f1(x) { var a = (x -= 3); return x += a; }
function f2(x) { var z = x, a = ++z; return z += a; }
}
expect: {
function f0(x) { var i = ++x; return x + i; }
function f1(x) { var a = (x -= 3); return x + a; }
function f2(x) { var z = x, a = ++z; return z + a; }
}
}
collapse_vars_misc1: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f10(x) { var a = 5, b = 3; return a += b; }
function f11(x) { var a = 5, b = 3; return a += --b; }
}
expect: {
function f10(x) { return 5 + 3; }
function f11(x) { var b = 3; return 5 + --b; }
}
}
return_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1(a, b, c) {
return a = x(), b = y(), b = a && (c >>= 5);
}
function f2() {
return e = x();
}
function f3(e) {
return e = x();
}
function f4() {
var e;
return e = x();
}
function f5(a) {
try {
return a = x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect: {
function f1(a, b, c) {
return a = x(), y(), a && (c >> 5);
}
function f2() {
return e = x();
}
function f3(e) {
return x();
}
function f4() {
return x();
}
function f5(a) {
try {
return x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect_stdout: [
"y",
"result 31",
"result 2",
"e: 2",
"result 3",
"result 4",
"result 5",
"6",
"result 6",
"caught -1",
"caught -2",
"caught -3",
"caught -4",
"50",
"result undefined",
"60",
"caught -6",
]
}
throw_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1() {
throw a = x();
}
function f2(a) {
throw a = x();
}
function f3() {
var a;
throw a = x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect: {
function f1() {
throw a = x();
}
function f2(a) {
throw x();
}
function f3() {
throw x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect_stdout: [
"caught 1",
"a: 1",
"caught 2",
"caught 3",
"4",
"a: 4",
"5",
"6",
"7",
"caught 7",
"a: 7",
"8",
"caught 8",
"9",
"caught 9",
"caught -1",
"caught -2",
"caught -3",
"null",
"50",
"undefined",
"null",
"caught -7",
"80",
"caught -8",
"undefined",
"caught -9",
]
}
issue_2597: {
options = {
dead_code: true,
}
input: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect_stdout: "PASS"
}
issue_2666: {
options = {
dead_code: true,
}
input: {
function f(a) {
return a = {
p: function() {
return a;
}
};
}
console.log(typeof f().p());
}
expect: {
function f(a) {
return a = {
p: function() {
return a;
}
};
}
console.log(typeof f().p());
}
expect_stdout: "object"
}
issue_2692: {
options = {
dead_code: true,
reduce_vars: false,
}
input: {
function f(a) {
return a = g;
function g() {
return a;
}
}
console.log(typeof f()());
}
expect: {
function f(a) {
return a = g;
function g() {
return a;
}
}
console.log(typeof f()());
}
expect_stdout: "function"
}
issue_2701: {
options = {
dead_code: true,
inline: false,
}
input: {
function f(a) {
return a = function() {
return function() {
return a;
};
}();
}
console.log(typeof f()());
}
expect: {
function f(a) {
return a = function() {
return function() {
return a;
};
}();
}
console.log(typeof f()());
}
expect_stdout: "function"
}
issue_2749: {
options = {
dead_code: true,
inline: true,
toplevel: true,
unused: true,
}
input: {
var a = 2, c = "PASS";
while (a--)
(function() {
return b ? c = "FAIL" : b = 1;
try {
} catch (b) {
var b;
}
})();
console.log(c);
}
expect: {
var a = 2, c = "PASS";
while (a--)
b = void 0, b ? c = "FAIL" : b = 1;
var b;
console.log(c);
}
expect_stdout: "PASS"
}
issue_2860_1: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
return a ^= 1;
}());
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_2860_2: {
options = {
dead_code: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
}
input: {
console.log(function(a) {
return a ^= 1;
}());
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_2929: {
options = {
dead_code: true,
}
input: {
console.log(function(a) {
try {
return null.p = a = 1;
} catch (e) {
return a ? "PASS" : "FAIL";
}
}());
}
expect: {
console.log(function(a) {
try {
return null.p = a = 1;
} catch (e) {
return a ? "PASS" : "FAIL";
}
}());
}
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: {
options = {
drop_debugger: false
};
drop_debugger: false,
}
input: {
debugger;
}
@@ -12,8 +12,8 @@ keep_debugger: {
drop_debugger: {
options = {
drop_debugger: true
};
drop_debugger: true,
}
input: {
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: {
options = {};
options = {}
input: {
console.log('foo');
console.log.apply(console, arguments);
@@ -11,7 +11,9 @@ drop_console_1: {
}
drop_console_2: {
options = { drop_console: true };
options = {
drop_console: true,
}
input: {
console.log('foo');
console.log.apply(console, arguments);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ must_replace: {
options = {
global_defs: {
D: "foo bar",
}
},
}
input: {
console.log(D);
@@ -37,6 +37,7 @@ object: {
VALUE: 42,
},
},
side_effects: true,
unsafe: true,
}
input: {
@@ -140,9 +141,8 @@ mixed: {
console.log(CONFIG);
}
expect_warnings: [
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]",
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]",
]
}
@@ -183,6 +183,7 @@ issue_2167: {
global_defs: {
"@isDevMode": "function(){}",
},
passes: 2,
side_effects: true,
}
input: {
@@ -195,3 +196,23 @@ issue_2167: {
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

@@ -0,0 +1,916 @@
issue_2377_1: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
var obj_foo = 1, obj_cube = function(x) {
return x * x * x;
};
console.log(obj_foo, obj_cube(3));
}
expect_stdout: "1 27"
}
issue_2377_2: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, (x = 3, x * x * x));
var x;
}
expect_stdout: "1 27"
}
issue_2377_3: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 4,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, 27);
}
expect_stdout: "1 27"
}
direct_access_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect_stdout: "2 1"
}
direct_access_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
var f = function(k) {
if (o[k]) return "PASS";
};
console.log(f("a"));
}
expect: {
var o = { a: 1 };
console.log(function(k) {
if (o[k]) return "PASS";
}("a"));
}
expect_stdout: "PASS"
}
direct_access_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect_stdout: "1"
}
single_use: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
bar: function() {
return 42;
},
};
console.log(obj.bar());
}
expect: {
console.log({
bar: function() {
return 42;
},
}.bar());
}
}
name_collision_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj = {
foo: 3,
bar: 4,
"b-r": 5,
"b+r": 6,
"b!r": 7,
};
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
}
f();
}
expect: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj_foo$0 = 3,
obj_bar = 4,
obj_b_r = 5,
obj_b_r$0 = 6,
obj_b_r$1 = 7;
console.log(obj_foo, obj_foo$0, obj_bar, obj_b_r, obj_b_r$0, obj_b_r$1);
}
f();
}
expect_stdout: "1 3 4 5 6 7"
}
name_collision_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
"+": function(x) {
return x;
},
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5), o__$0, o__$1);
}
expect_stdout: "true 4 6 2 3"
}
name_collision_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
"+": function(x) {
return x;
},
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o["+"](4), o["-"](5));
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5));
}
expect_stdout: "true 4 6"
}
contains_this_1: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p);
}
expect: {
console.log(1, 1);
}
expect_stdout: "1 1"
}
contains_this_2: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u);
}
expect: {
console.log(1, 1, function() {
return this === this;
});
}
expect_stdout: true
}
contains_this_3: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect_stdout: "1 1 true"
}
new_this: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
f: function(a) {
this.b = a;
}
};
console.log(new o.f(o.a).b, o.b);
}
expect: {
console.log(new function(a) {
this.b = a;
}(1).b, 2);
}
expect_stdout: "1 2"
}
issue_2473_1: {
options = {
hoist_props: false,
reduce_vars: true,
top_retain: [
"x",
"y"
],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_2: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: [
"x",
"y"
],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_3: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect_stdout: "1 2"
}
issue_2473_4: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
(function() {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
})();
}
expect: {
(function() {
var o_a = 1, o_b = 2;
console.log(o_a, o_b);
})();
}
expect_stdout: "1 2"
}
issue_2508_1: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ 1 ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})([ 1 ]);
}
expect_stdout: true
}
issue_2508_2: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: 2 },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})({ b: 2 });
}
expect_stdout: true
}
issue_2508_3: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_4: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_5: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: function(x) {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = function(x) {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2519: {
options = {
collapse_vars: true,
evaluate: true,
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
function testFunc() {
var dimensions = {
minX: 5,
maxX: 6,
};
var scale = 1;
var d = {
x: (dimensions.maxX + dimensions.minX) / 2,
};
return d.x * scale;
}
console.log(testFunc());
}
expect: {
function testFunc() {
return +((6 + 5) / 2);
}
console.log(testFunc());
}
expect_stdout: "5.5"
}
undefined_key: {
options = {
evaluate: true,
hoist_props: true,
join_vars: true,
passes: 4,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a, o = {};
o[a] = 1;
o.b = 2;
console.log(o[a] + o.b);
}
expect: {
console.log(3);
}
expect_stdout: "3"
}
issue_3021: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var a = 1, b = 2;
(function() {
b = a;
if (a++ + b--)
return 1;
return;
var b = {};
})();
console.log(a, b);
}
expect: {
var a = 1, b = 2;
(function() {
b = a;
if (a++ + b--)
return 1;
return;
var b = {};
})();
console.log(a, b);
}
expect_stdout: "2 2"
}
issue_3046: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
do {
var b = {
c: a++
};
} while (b.c && a);
return a;
}(0));
}
expect: {
console.log(function(a) {
do {
var b_c = a++;
} while (b_c && a);
return a;
}(0));
}
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

@@ -88,3 +88,24 @@ sequences_funs: {
}
}
}
issue_2295: {
options = {
collapse_vars: true,
hoist_vars: true,
}
input: {
function foo(o) {
var a = o.a;
if (a) return a;
var a = 1;
}
}
expect: {
function foo(o) {
var a = o.a;
if (a) return a;
a = 1;
}
}
}

View File

@@ -1,55 +1,107 @@
html_comment_in_expression: {
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: {
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: {
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}";
}
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}";
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_greater_than: {
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: {
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: {
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"
}

2422
test/compress/ie8.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
if_return_1: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
@@ -24,15 +24,15 @@ if_return_1: {
if_return_2: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x, y) {
@@ -49,15 +49,15 @@ if_return_2: {
if_return_3: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
@@ -75,15 +75,15 @@ if_return_3: {
if_return_4: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x, y) {
@@ -100,15 +100,15 @@ if_return_4: {
if_return_5: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f() {
@@ -126,15 +126,15 @@ if_return_5: {
if_return_6: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
@@ -150,15 +150,15 @@ if_return_6: {
if_return_7: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
@@ -176,10 +176,10 @@ if_return_7: {
if_return_8: {
options = {
if_return: true,
sequences: true,
conditionals: true,
side_effects : true,
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
}
input: {
function f(e) {
@@ -220,15 +220,15 @@ if_return_8: {
issue_1089: {
options = {
if_return : true,
sequences : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
unused : true,
side_effects : true,
dead_code : true,
booleans: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
if_return: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function x() {
@@ -243,7 +243,7 @@ issue_1089: {
expect: {
function x() {
var f = document.getElementById("fname");
if (f.files[0].size > 12345)
if (12345 < f.files[0].size)
return alert("alert"), f.focus(), !1;
}
}
@@ -251,9 +251,9 @@ issue_1089: {
issue_1437: {
options = {
if_return : true,
sequences : true,
conditionals : false
conditionals: false,
if_return: true,
sequences: true,
}
input: {
function x() {
@@ -281,9 +281,9 @@ issue_1437: {
issue_1437_conditionals: {
options = {
conditionals : true,
if_return : true,
sequences : true
conditionals: true,
if_return: true,
sequences: true,
}
input: {
function x() {
@@ -326,3 +326,250 @@ issue_512: {
}
}
}
if_var_return: {
options = {
conditionals: true,
if_return: true,
join_vars: true,
sequences: true,
}
input: {
function f() {
var a;
return;
var b;
}
function g() {
var a;
if (u()) {
var b;
return v();
var c;
}
var d;
if (w()) {
var e;
return x();
var f;
} else {
var g;
y();
var h;
}
var i;
z();
var j;
}
}
expect: {
function f() {
var a, b;
}
function g() {
var a, b, c, d, e, f, g, h, i, j;
return u() ? v() : w() ? x() : (y(), z(), void 0);
}
}
}
if_if_return_return: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f(a, b) {
if (a) {
if (b)
return b;
return;
}
g();
}
}
expect: {
function f(a, b) {
if (a)
return b || void 0;
g();
}
}
}
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: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true
booleans: true,
comparisons: 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: {
function foo(x) {
@@ -21,25 +30,35 @@ non_hoisted_function_after_return: {
}
expect: {
function foo(x) {
return x ? bar() : baz();
return (x ? bar : baz)();
function bar() { return 7 }
function baz() { return 8 }
}
}
expect_warnings: [
'WARN: Dropping unreachable code [test/compress/issue-1034.js:11,16]',
"WARN: Dropping unreachable code [test/compress/issue-1034.js:14,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:17,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:18,21]"
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
]
}
non_hoisted_function_after_return_2a: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
booleans: true,
collapse_vars: false,
comparisons: true,
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: {
function foo(x) {
@@ -65,26 +84,37 @@ non_hoisted_function_after_return_2a: {
}
}
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:48,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:48,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
"INFO: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
"INFO: pass 1: last_count: 37, count: 18",
]
}
non_hoisted_function_after_return_2b: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false
booleans: true,
collapse_vars: false,
comparisons: 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: {
function foo(x) {
@@ -108,20 +138,28 @@ non_hoisted_function_after_return_2b: {
}
}
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
]
}
non_hoisted_function_after_return_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true
booleans: true,
comparisons: 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: {
"use strict";
@@ -143,7 +181,7 @@ non_hoisted_function_after_return_strict: {
expect: {
"use strict";
function foo(x) {
return x ? bar() : baz();
return (x ? bar : baz)();
function bar() { return 7 }
function baz() { return 8 }
}
@@ -151,19 +189,29 @@ non_hoisted_function_after_return_strict: {
}
expect_stdout: "8 7"
expect_warnings: [
'WARN: Dropping unreachable code [test/compress/issue-1034.js:131,16]',
"WARN: Dropping unreachable code [test/compress/issue-1034.js:134,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:137,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:138,21]"
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:11,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:12,21]",
]
}
non_hoisted_function_after_return_2a_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
booleans: true,
collapse_vars: false,
comparisons: true,
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: {
"use strict";
@@ -194,26 +242,37 @@ non_hoisted_function_after_return_2a_strict: {
}
expect_stdout: "5 6"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:173,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:173,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:176,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:176,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:173,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:180,21]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:181,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:176,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:178,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
"INFO: pass 0: last_count: Infinity, count: 48",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
"INFO: pass 1: last_count: 48, count: 29",
]
}
non_hoisted_function_after_return_2b_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false
booleans: true,
collapse_vars: false,
comparisons: 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: {
"use strict";
@@ -242,11 +301,10 @@ non_hoisted_function_after_return_2b_strict: {
}
expect_stdout: "5 6"
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
]
}

View File

@@ -1,8 +1,9 @@
const_pragma: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};
}
input: {
/** @const */ var goog = goog || {};
@@ -16,8 +17,9 @@ const_pragma: {
not_const: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};
}
input: {
var goog = goog || {};

View File

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

View File

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

View File

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

View File

@@ -1,15 +1,14 @@
pure_function_calls: {
options = {
evaluate : true,
conditionals : true,
comparisons : true,
side_effects : true,
booleans : true,
unused : true,
if_return : true,
join_vars : true,
cascade : true,
negate_iife : true,
booleans: true,
comparisons: true,
conditionals: true,
evaluate: true,
if_return: true,
join_vars: true,
negate_iife: true,
side_effects: true,
unused: true,
}
input: {
// pure top-level IIFE will be dropped
@@ -49,29 +48,28 @@ pure_function_calls: {
a.b(), f.g();
}
expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:25,31]",
]
}
pure_function_calls_toplevel: {
options = {
evaluate : true,
conditionals : true,
comparisons : true,
side_effects : true,
booleans : true,
unused : true,
if_return : true,
join_vars : true,
cascade : true,
negate_iife : true,
toplevel : true,
booleans: true,
comparisons: true,
conditionals: true,
evaluate: true,
if_return: true,
join_vars: true,
negate_iife: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
// pure top-level IIFE will be dropped
@@ -96,6 +94,13 @@ pure_function_calls_toplevel: {
})();
})();
// pure top-level calls will be dropped regardless of the leading comments position
var MyClass = /*#__PURE__*//*@class*/(function(){
function MyClass() {}
MyClass.prototype.method = function() {};
return MyClass;
})();
// comment #__PURE__ comment
bar(), baz(), quux();
a.b(), /* @__PURE__ */ c.d.e(), f.g();
@@ -105,15 +110,17 @@ pure_function_calls_toplevel: {
a.b(), f.g();
}
expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:31,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:32,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:8,12]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,45]",
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:24,12]",
]
}
@@ -148,29 +155,29 @@ should_warn: {
baz();
}
expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
"WARN: Condition left of || always true [test/compress/issue-1261.js:130,8]",
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
"WARN: Condition left of && always false [test/compress/issue-1261.js:132,8]",
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
"WARN: Condition always true [test/compress/issue-1261.js:136,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
"WARN: Condition always false [test/compress/issue-1261.js:137,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,61]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:1,23]",
"WARN: Boolean || always true [test/compress/issue-1261.js:2,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:2,23]",
"WARN: Condition always true [test/compress/issue-1261.js:2,23]",
"WARN: Condition left of || always true [test/compress/issue-1261.js:3,8]",
"WARN: Condition always true [test/compress/issue-1261.js:3,8]",
"WARN: Boolean && always false [test/compress/issue-1261.js:4,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:4,23]",
"WARN: Condition always false [test/compress/issue-1261.js:4,23]",
"WARN: Condition left of && always false [test/compress/issue-1261.js:5,8]",
"WARN: Condition always false [test/compress/issue-1261.js:5,8]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:6,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:6,23]",
"WARN: Condition always true [test/compress/issue-1261.js:6,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:7,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:7,31]",
"WARN: Condition always true [test/compress/issue-1261.js:7,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,23]",
"WARN: Condition always true [test/compress/issue-1261.js:9,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:9,24]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:10,31]",
"WARN: Condition always false [test/compress/issue-1261.js:10,8]",
]
}

View File

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

View File

@@ -1,6 +1,8 @@
issue_1321_no_debug: {
mangle_props = {
keep_quoted: true
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
var x = {};
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
}
expect: {
var x = {};
x.o = 1;
x["a"] = 2 * x.o;
console.log(x.o, x["a"]);
x.x = 1;
x["a"] = 2 * x.x;
console.log(x.x, x["a"]);
}
expect_stdout: true
}
issue_1321_debug: {
mangle_props = {
keep_quoted: true,
debug: ""
mangle = {
properties: {
debug: "",
keep_quoted: true,
},
}
input: {
var x = {};
@@ -30,16 +34,18 @@ issue_1321_debug: {
}
expect: {
var x = {};
x.o = 1;
x["_$foo$_"] = 2 * x.o;
console.log(x.o, x["_$foo$_"]);
x.x = 1;
x["_$foo$_"] = 2 * x.x;
console.log(x.x, x["_$foo$_"]);
}
expect_stdout: true
}
issue_1321_with_quoted: {
mangle_props = {
keep_quoted: false
mangle = {
properties: {
keep_quoted: false,
},
}
input: {
var x = {};
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
}
expect: {
var x = {};
x.o = 1;
x["x"] = 2 * x.o;
console.log(x.o, x["x"]);
x.x = 1;
x["o"] = 2 * x.x;
console.log(x.x, x["o"]);
}
expect_stdout: true
}

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true
unsafe_undefined: true,
}
mangle = {}
input: {
@@ -30,7 +30,7 @@ keep_fnames: {
options = {
conditionals: true,
if_return: true,
unsafe: true
unsafe_undefined: true,
}
mangle = {
keep_fnames: true

View File

@@ -1,6 +1,7 @@
typeof_eq_undefined: {
options = {
comparisons: true
comparisons: true,
typeofs: true,
}
input: {
var a = typeof b != "undefined";
@@ -24,6 +25,7 @@ typeof_eq_undefined_ie8: {
options = {
comparisons: true,
ie8: true,
typeofs: true,
}
input: {
var a = typeof b != "undefined";
@@ -45,7 +47,8 @@ typeof_eq_undefined_ie8: {
undefined_redefined: {
options = {
comparisons: true
comparisons: true,
typeofs: true,
}
input: {
function f(undefined) {
@@ -58,7 +61,8 @@ undefined_redefined: {
undefined_redefined_mangle: {
options = {
comparisons: true
comparisons: true,
typeofs: true,
}
mangle = {}
input: {

View File

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

View File

@@ -61,7 +61,7 @@ unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true,
unsafe_undefined: true,
}
mangle = {}
input: {

View File

@@ -2,6 +2,7 @@ chained_evaluation_1: {
options = {
collapse_vars: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -28,6 +29,7 @@ chained_evaluation_2: {
options = {
collapse_vars: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -50,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,8 +1,7 @@
issue_1639_1: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
join_vars: true,
@@ -12,7 +11,6 @@ issue_1639_1: {
}
input: {
var a = 100, b = 10;
var L1 = 5;
while (--L1 > 0) {
if ((--b), false) {
@@ -21,21 +19,20 @@ issue_1639_1: {
}
}
}
console.log(a, b);
}
expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, !1) var ignore = 0;
if (--b, 0) var ignore = 0;
console.log(a, b);
}
expect_stdout: true
expect_stdout: "100 6"
}
issue_1639_2: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
join_vars: true,
@@ -44,14 +41,12 @@ issue_1639_2: {
}
input: {
var a = 100, b = 10;
function f19() {
if (++a, false)
if (a)
if (++a);
}
f19();
console.log(a, b);
}
expect: {
@@ -62,13 +57,13 @@ issue_1639_2: {
f19(),
console.log(a, b);
}
expect_stdout: true
expect_stdout: "101 10"
}
issue_1639_3: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
sequences: true,
@@ -84,5 +79,5 @@ issue_1639_3: {
a++,
console.log(a, b);
}
expect_stdout: true
expect_stdout: "101 10"
}

View File

@@ -1,7 +1,6 @@
f7: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
@@ -15,6 +14,7 @@ f7: {
negate_iife: true,
passes: 3,
properties: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -38,7 +38,7 @@ f7: {
"var b = 10;",
"",
"!function() {",
" for (;b = 100, !1; ) ;",
" b = 100;",
"}(), console.log(100, b);",
]
expect_stdout: true

View File

@@ -1,5 +1,6 @@
side_effects_catch: {
options = {
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -34,6 +35,7 @@ side_effects_catch: {
side_effects_else: {
options = {
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -62,6 +64,7 @@ side_effects_else: {
side_effects_finally: {
options = {
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -98,6 +101,7 @@ side_effects_finally: {
side_effects_label: {
options = {
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -130,6 +134,7 @@ side_effects_label: {
side_effects_switch: {
options = {
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,

View File

@@ -104,7 +104,7 @@ mangle_catch_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_exact: 'var c="FAIL";try{throw 1}catch(o){c="PASS"}console.log(c);'
expect_stdout: "PASS"
}
@@ -148,7 +148,7 @@ mangle_catch_var_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_exact: 'var r="FAIL";try{throw 1}catch(o){var r="PASS"}console.log(r);'
expect_stdout: "PASS"
}
@@ -345,3 +345,95 @@ mangle_catch_redef_2_ie8_toplevel: {
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
mangle_catch_redef_3: {
mangle = {
ie8: false,
toplevel: false,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
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: true
}
mangle_catch_redef_3_toplevel: {
mangle = {
ie8: false,
toplevel: true,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: true
}
mangle_catch_redef_3_ie8: {
mangle = {
ie8: true,
toplevel: false,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
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: true
}
mangle_catch_redef_3_ie8_toplevel: {
mangle = {
ie8: true,
toplevel: true,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: true
}

View File

@@ -15,7 +15,7 @@ function_iife_catch: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
@@ -36,7 +36,7 @@ function_iife_catch_ie8: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
@@ -61,7 +61,7 @@ function_catch_catch: {
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();"
expect_stdout: [
"3",
"undefined",

View File

@@ -7,7 +7,7 @@ case_1: {
input: {
var a = 0, b = 1;
switch (true) {
case a, true:
case a || true:
default:
b = 2;
case true:
@@ -17,7 +17,7 @@ case_1: {
expect: {
var a = 0, b = 1;
switch (true) {
case a, true:
case a || true:
b = 2;
}
console.log(a, b);

View File

@@ -1,5 +1,7 @@
mangle_props: {
mangle_props = {}
mangle = {
properties: true,
}
input: {
var obj = {
undefined: 1,
@@ -44,7 +46,7 @@ mangle_props: {
obj[1/0],
obj["Infinity"],
obj[-1/0],
obj[-1/0],
obj[-(1/0)],
obj["-Infinity"],
obj[null],
obj["null"]
@@ -54,10 +56,12 @@ mangle_props: {
}
numeric_literal: {
mangle = {
properties: true,
}
beautify = {
beautify: true,
}
mangle_props = {}
input: {
var obj = {
0: 0,
@@ -80,12 +84,12 @@ numeric_literal: {
' 0: 0,',
' "-0": 1,',
' 42: 2,',
' "42": 3,',
' 42: 3,',
' 37: 4,',
' o: 5,',
' 1e42: 6,',
' b: 7,',
' "1e+42": 8',
' 1e42: 8',
'};',
'',
'console.log(obj[-0], obj[-""], obj["-0"]);',
@@ -105,7 +109,9 @@ numeric_literal: {
}
identifier: {
mangle_props = {}
mangle = {
properties: true,
}
input: {
var obj = {
abstract: 1,

View File

@@ -2,6 +2,7 @@ unary_prefix: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}

View File

@@ -1,6 +1,7 @@
iife_for: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -26,6 +27,7 @@ iife_for: {
iife_for_in: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -51,6 +53,7 @@ iife_for_in: {
iife_do: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -80,6 +83,7 @@ iife_do: {
iife_while: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -121,8 +125,8 @@ label_do: {
label_while: {
options = {
evaluate: true,
dead_code: true,
evaluate: true,
loops: true,
}
input: {
@@ -130,5 +134,5 @@ label_while: {
L: while (0) continue L;
}
}
expect_exact: "function f(){L:;}"
expect_exact: "function f(){L:0}"
}

View File

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

View File

@@ -0,0 +1,33 @@
insert_semicolon: {
beautify = {
beautify: true,
comments: "all",
}
input: {
var a
/* foo */ var b
}
expect_exact: [
"var a",
"/* foo */;",
"",
"var b;",
]
}
unary_postfix: {
beautify = {
beautify: true,
comments: "all",
}
input: {
a
/* foo */++b
}
expect_exact: [
"a",
"/* foo */;",
"",
"++b;",
]
}

View File

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

View File

@@ -1,66 +1,111 @@
issue_269_1: {
options = {unsafe: true};
input: {
f(
String(x),
Number(x),
Boolean(x),
options = {
unsafe: true,
}
input: {
var x = {};
console.log(
String(x),
Number(x),
Boolean(x),
String(),
Number(),
Boolean()
);
}
expect: {
f(
x + '', +x, !!x,
'', 0, false
);
}
String(),
Number(),
Boolean()
);
}
expect: {
var x = {};
console.log(
x + "", +x, !!x,
"", 0, false
);
}
expect_stdout: true
}
issue_269_dangers: {
options = {unsafe: true};
input: {
f(
String(x, x),
Number(x, x),
Boolean(x, x)
);
}
expect: {
f(String(x, x), Number(x, x), Boolean(x, x));
}
options = {
unsafe: true,
}
input: {
var x = {};
console.log(
String(x, x),
Number(x, x),
Boolean(x, x)
);
}
expect: {
var x = {};
console.log(String(x, x), Number(x, x), Boolean(x, x));
}
expect_stdout: true
}
issue_269_in_scope: {
options = {unsafe: true};
input: {
var String, Number, Boolean;
f(
String(x),
Number(x, x),
Boolean(x)
);
}
expect: {
var String, Number, Boolean;
f(String(x), Number(x, x), Boolean(x));
}
options = {
unsafe: true,
}
input: {
var String, Number, Boolean;
var x = {};
console.log(
String(x),
Number(x, x),
Boolean(x)
);
}
expect: {
var String, Number, Boolean;
var x = {};
console.log(String(x), Number(x, x), Boolean(x));
}
expect_stdout: true
}
strings_concat: {
options = {unsafe: true};
input: {
f(
String(x + 'str'),
String('str' + x)
);
}
expect: {
f(
x + 'str',
'str' + x
);
}
options = {
strings: true,
unsafe: true,
}
input: {
var x = {};
console.log(
String(x + "str"),
String("str" + x)
);
}
expect: {
var x = {};
console.log(
x + "str",
"str" + x
);
}
expect_stdout: true
}
regexp: {
options = {
evaluate: true,
unsafe: true,
}
input: {
RegExp("foo");
RegExp("bar", "ig");
RegExp(foo);
RegExp("bar", ig);
RegExp("should", "fail");
}
expect: {
/foo/;
/bar/ig;
RegExp(foo);
RegExp("bar", ig);
RegExp("should", "fail");
}
expect_warnings: [
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,8]',
]
}

View File

@@ -0,0 +1,32 @@
warn: {
options = {
evaluate: true,
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
return g();
}
function g() {
return g["call" + "er"].arguments;
}
// 3
console.log(f(1, 2, 3).length);
}
expect: {
// TypeError: Cannot read property 'arguments' of null
console.log(function g() {
return g.caller.arguments;
}().length);
}
expect_warnings: [
"WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
]
}

View File

@@ -3,6 +3,7 @@ collapse_vars_constants: {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -185,7 +186,7 @@ negate_iife_5_off: {
inline: true,
negate_iife: false,
sequences: true,
};
}
input: {
if ((function(){ return t })()) {
foo(true);
@@ -240,10 +241,11 @@ negate_iife_issue_1073: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
unused: true,
};
}
input: {
new (function(a) {
return function Foo() {
@@ -267,10 +269,11 @@ issue_1288_side_effects: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
};
}
input: {
if (w) ;
else {
@@ -299,6 +302,7 @@ inner_var_for_in_1: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -330,6 +334,7 @@ issue_1595_3: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -394,7 +399,7 @@ wrap_iife_in_expression: {
wrap_iife: true,
}
input: {
foo = (function () {
foo = (function() {
return bar();
})();
}
@@ -448,7 +453,7 @@ pure_annotation_2: {
drop_fargs: {
options = {
cascade: true,
collapse_vars: true,
inline: true,
keep_fargs: false,
side_effects: true,
@@ -471,7 +476,7 @@ drop_fargs: {
keep_fargs: {
options = {
cascade: true,
collapse_vars: true,
inline: true,
keep_fargs: true,
side_effects: true,

View File

@@ -0,0 +1,37 @@
comparison_with_undefined: {
options = {
comparisons: true,
}
input: {
a == undefined;
a != undefined;
a === undefined;
a !== undefined;
undefined == a;
undefined != a;
undefined === a;
undefined !== a;
void 0 == a;
void 0 != a;
void 0 === a;
void 0 !== a;
}
expect: {
null == a;
null != a;
void 0 === a;
void 0 !== a;
null == a;
null != a;
void 0 === a;
void 0 !== a;
null == a;
null != a;
void 0 === a;
void 0 !== a;
}
}

View File

@@ -0,0 +1,21 @@
inline_script_off: {
beautify = {
inline_script: false,
}
input: {
console.log("</sCrIpT>");
}
expect_exact: 'console.log("</sCrIpT>");'
expect_stdout: "</sCrIpT>"
}
inline_script_on: {
beautify = {
inline_script: true,
}
input: {
console.log("</sCrIpT>");
}
expect_exact: 'console.log("<\\/sCrIpT>");'
expect_stdout: "</sCrIpT>"
}

View File

@@ -1,6 +1,6 @@
collapse: {
options = {
cascade: true,
collapse_vars: true,
sequences: true,
side_effects: true,
unused: true,
@@ -41,7 +41,7 @@ collapse: {
return void 0 !== ('function' === typeof b ? b() : b) && c();
}
function f2(b) {
return b = c(), 'stirng' == typeof ('function' === typeof b ? b() : b) && d();
return 'stirng' == typeof ('function' === typeof (b = c()) ? b() : b) && d();
}
function f3(c) {
var a;

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,8 @@
dont_reuse_prop: {
mangle_props = {
regex: /asd/
mangle = {
properties: {
regex: /asd/,
},
}
input: {
"aaaaaaaaaabbbbb";
@@ -20,8 +22,10 @@ dont_reuse_prop: {
}
unmangleable_props_should_always_be_reserved: {
mangle_props = {
regex: /asd/
mangle = {
properties: {
regex: /asd/,
},
}
input: {
"aaaaaaaaaabbbbb";

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,11 @@
this_binding_conditionals: {
options = {
conditionals: true,
evaluate : true
};
evaluate: true,
side_effects: true,
}
input: {
"use strict";
(1 && a)();
(0 || a)();
(0 || 1 && a)();
@@ -25,6 +27,7 @@ this_binding_conditionals: {
(1 ? eval : 0)();
}
expect: {
"use strict";
a();
a();
a();
@@ -50,48 +53,111 @@ this_binding_conditionals: {
this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
};
unused: true,
}
input: {
var c = a; c();
var d = a.b; d();
var e = eval; e();
function f() {
"use strict";
var c = a; c();
var d = a.b; d();
var e = eval; e();
}
}
expect: {
a();
(0, a.b)();
(0, eval)();
function f() {
"use strict";
a();
(0, a.b)();
(0, eval)();
}
}
}
this_binding_side_effects: {
options = {
side_effects : true
};
side_effects: true,
}
input: {
(function (foo) {
(function(foo) {
(0, foo)();
(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;
(0, foo)();
(0, foo.bar)();
(0, eval)('console.log(foo);');
(0, eval)("console.log(foo);");
}());
}
expect: {
(function (foo) {
(function(foo) {
foo();
(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;
foo();
(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: {
options = {
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
};
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: true,
properties: true,
sequences: false,
side_effects: true,
unused: true,
}
input: {
function f1() {
var e = 7;
@@ -46,7 +58,10 @@ eval_collapse_vars: {
}
eval_unused: {
options = { unused: true, keep_fargs: false };
options = {
keep_fargs: false,
unused: true,
}
input: {
function f1(a, eval, c, d, e) {
return a('c') + eval;

View File

@@ -1,8 +1,19 @@
issue979_reported: {
options = {
sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
booleans: 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: {
function f1() {
@@ -30,9 +41,20 @@ issue979_reported: {
issue979_test_negated_is_best: {
options = {
sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
booleans: 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: {
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: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
out: {
if (foo) break out;
@@ -13,7 +17,11 @@ labels_1: {
}
labels_2: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
out: {
if (foo) print("stuff");
@@ -30,7 +38,11 @@ labels_2: {
}
labels_3: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
for (var i = 0; i < 5; ++i) {
if (i < 3) continue;
@@ -45,7 +57,11 @@ labels_3: {
}
labels_4: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
out: for (var i = 0; i < 5; ++i) {
if (i < 3) continue out;
@@ -60,7 +76,11 @@ labels_4: {
}
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
input: {
while (foo) {
@@ -92,7 +112,11 @@ labels_6: {
}
labels_7: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
while (foo) {
x();
@@ -109,7 +133,11 @@ labels_7: {
}
labels_8: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
while (foo) {
x();
@@ -127,7 +155,11 @@ labels_8: {
}
labels_9: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
out: while (foo) {
x();
@@ -146,7 +178,11 @@ labels_9: {
}
labels_10: {
options = { if_return: true, conditionals: true, dead_code: true };
options = {
conditionals: true,
dead_code: true,
if_return: true,
}
input: {
out: while (foo) {
x();

View File

@@ -1,37 +1,45 @@
while_becomes_for: {
options = { loops: true };
options = {
loops: true,
}
input: {
while (foo()) bar();
}
expect: {
for (; foo(); ) bar();
for (;foo();) bar();
}
}
drop_if_break_1: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;;)
if (foo()) break;
}
expect: {
for (; !foo(););
for (;!foo(););
}
}
drop_if_break_2: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;bar();)
if (foo()) break;
}
expect: {
for (; bar() && !foo(););
for (;bar() && !foo(););
}
}
drop_if_break_3: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;bar();) {
if (foo()) break;
@@ -48,7 +56,10 @@ drop_if_break_3: {
}
drop_if_break_4: {
options = { loops: true, sequences: true };
options = {
loops: true,
sequences: true,
}
input: {
for (;bar();) {
x();
@@ -59,22 +70,26 @@ drop_if_break_4: {
}
}
expect: {
for (; bar() && (x(), y(), !foo());) z(), k();
for (;bar() && (x(), y(), !foo());) z(), k();
}
}
drop_if_else_break_1: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;;) if (foo()) bar(); else break;
}
expect: {
for (; foo(); ) bar();
for (;foo();) bar();
}
}
drop_if_else_break_2: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;bar();) {
if (foo()) baz();
@@ -82,12 +97,14 @@ drop_if_else_break_2: {
}
}
expect: {
for (; bar() && foo();) baz();
for (;bar() && foo();) baz();
}
}
drop_if_else_break_3: {
options = { loops: true };
options = {
loops: true,
}
input: {
for (;bar();) {
if (foo()) baz();
@@ -97,7 +114,7 @@ drop_if_else_break_3: {
}
}
expect: {
for (; bar() && foo();) {
for (;bar() && foo();) {
baz();
stuff1();
stuff2();
@@ -106,7 +123,10 @@ drop_if_else_break_3: {
}
drop_if_else_break_4: {
options = { loops: true, sequences: true };
options = {
loops: true,
sequences: true,
}
input: {
for (;bar();) {
x();
@@ -118,12 +138,14 @@ drop_if_else_break_4: {
}
}
expect: {
for (; bar() && (x(), y(), foo());) baz(), z(), k();
for (;bar() && (x(), y(), foo());) baz(), z(), k();
}
}
parse_do_while_with_semicolon: {
options = { loops: false };
options = {
loops: false,
}
input: {
do {
x();
@@ -135,7 +157,9 @@ parse_do_while_with_semicolon: {
}
parse_do_while_without_semicolon: {
options = { loops: false };
options = {
loops: false,
}
input: {
do {
x();
@@ -148,10 +172,12 @@ parse_do_while_without_semicolon: {
evaluate: {
options = {
loops: true,
dead_code: true,
evaluate: true,
};
loops: true,
passes: 2,
side_effects: true,
}
input: {
while (true) {
a();
@@ -292,10 +318,10 @@ issue_186_beautify_ie8: {
]
}
issue_186_bracketize: {
issue_186_braces: {
beautify = {
beautify: false,
bracketize: true,
braces: true,
ie8: false,
}
input: {
@@ -312,10 +338,10 @@ issue_186_bracketize: {
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_bracketize_ie8: {
issue_186_braces_ie8: {
beautify = {
beautify: false,
bracketize: true,
braces: true,
ie8: true,
}
input: {
@@ -332,10 +358,10 @@ issue_186_bracketize_ie8: {
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_beautify_bracketize: {
issue_186_beautify_braces: {
beautify = {
beautify: true,
bracketize: true,
braces: true,
ie8: false,
}
input: {
@@ -364,10 +390,10 @@ issue_186_beautify_bracketize: {
]
}
issue_186_beautify_bracketize_ie8: {
issue_186_beautify_braces_ie8: {
beautify = {
beautify: true,
bracketize: true,
braces: true,
ie8: true,
}
input: {
@@ -436,3 +462,468 @@ do_switch: {
} while (false);
}
}
in_parenthesis_1: {
input: {
for (("foo" in {});0;);
}
expect_exact: 'for(("foo"in{});0;);'
}
in_parenthesis_2: {
input: {
for ((function(){ "foo" in {}; });0;);
}
expect_exact: 'for(function(){"foo"in{}};0;);'
}
init_side_effects: {
options = {
loops: true,
side_effects: true,
}
input: {
for (function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 10; i++) console.log(i);
}
expect: {
for (i = 0; i < 5; i++) console.log(i);
for (; i < 10; i++) console.log(i);
}
expect_stdout: true
}
dead_code_condition: {
options = {
dead_code: true,
evaluate: true,
loops: true,
sequences: true,
}
input: {
for (var a = 0, b = 5; (a += 1, 3) - 3 && b > 0; b--) {
var c = function() {
b--;
}(a++);
}
console.log(a);
}
expect: {
var c;
var a = 0, b = 5;
a += 1, 0,
console.log(a);
}
expect_stdout: "1"
}
issue_2740_1: {
options = {
dead_code: true,
loops: true,
}
input: {
for (;;) break;
for (a();;) break;
for (;b();) break;
for (c(); d();) break;
for (;;e()) break;
for (f();; g()) break;
for (;h(); i()) break;
for (j(); k(); l()) break;
}
expect: {
a();
b();
c();
d();
f();
h();
j();
k();
}
}
issue_2740_2: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: while (x()) {
break L1;
}
}
expect: {
x();
}
}
issue_2740_3: {
options = {
dead_code: true,
loops: true,
}
input: {
L1: for (var x = 0; x < 3; x++) {
L2: for (var y = 0; y < 2; y++) {
break L1;
}
}
console.log(x, y);
}
expect: {
L1: for (var x = 0; x < 3; x++) {
var y = 0;
if (y < 2)
break L1;
}
console.log(x, y);
}
expect_stdout: "0 0"
}
issue_2740_4: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: for (var x = 0; x < 3; x++) {
L2: for (var y = 0; y < 2; y++) {
break L2;
}
}
console.log(x, y);
}
expect: {
for (var x = 0; x < 3; x++) {
var y = 0;
y < 2;
}
console.log(x, y);
}
expect_stdout: "3 0"
}
issue_2740_5: {
options = {
dead_code: true,
loops: true,
passes: 2,
}
input: {
L1: for (var x = 0; x < 3; x++) {
break L1;
L2: for (var y = 0; y < 2; y++) {
break L2;
}
}
console.log(x, y);
}
expect: {
var x = 0;
x < 3;
var y;
console.log(x,y);
}
expect_stdout: "0 undefined"
}
issue_2904: {
options = {
join_vars: true,
loops: true,
}
input: {
var a = 1;
do {
console.log(a);
} while (--a);
}
expect: {
for (var a = 1; console.log(a), --a;);
}
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: [
'function f(a){',
'return{',
'c:42,',
'd:a(),',
'e:"foo"}}',
"function f(",
"a){return{",
"c:42,d:a(",
'),e:"foo"}',
"}",
]
expect_warnings: [
"WARN: Output exceeds 10 characters"
"WARN: Output exceeds 10 characters",
]
}
@@ -29,11 +29,25 @@ just_enough: {
}
}
expect_exact: [
'function f(a){',
'return{c:42,',
"function f(a){",
"return{c:42,",
'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: []
}

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