Compare commits

...

217 Commits

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

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

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

fixes #3689
2020-01-28 07:33:11 +08:00
Alex Lam S.L
0dcedad2d5 fix corner case in booleans (#3691)
fixes #3690
2020-01-28 02:04:44 +08:00
Alex Lam S.L
36a430cd1e v3.7.6 2020-01-19 11:02:58 +00:00
Alex Lam S.L
41a6eb892a fix corner case in evaluate (#3685)
fixes #3684
2020-01-16 01:51:37 +08:00
Alex Lam S.L
91d87ae663 fix corner case in unsafe_math (#3683)
fixes #3682
2020-01-15 04:05:58 +08:00
Alex Lam S.L
5beb7e4797 v3.7.5 2020-01-12 11:12:11 +08:00
Alex Lam S.L
46caaa82ba enhance collapse_vars (#3680)
closes #3679
2020-01-10 04:28:43 +08:00
Alex Lam S.L
5d258259a4 introduce --output-opts CLI option (#3678)
closes #3675
2020-01-08 20:44:03 +08:00
Alex Lam S.L
14c35739dd fix corner case in unsafe_math (#3677)
fixes #3676
2020-01-08 10:28:10 +08:00
Alex Lam S.L
f5ceff6e4b fix corner case in unused (#3674)
fixes #3673
2020-01-07 20:06:25 +08:00
Alex Lam S.L
4d6771b9b1 fix corner case in collapse_vars (#3672)
fixes #3671
2020-01-07 19:34:16 +08:00
Alex Lam S.L
d17191111a v3.7.4 2020-01-07 07:59:54 +08:00
Alex Lam S.L
0ff607cb80 improve ufuzz false positive detection (#3670) 2020-01-06 11:26:15 +08:00
Alex Lam S.L
1988495d71 fix corner case in conditionals (#3669)
fixes #3668
2020-01-04 09:24:28 +08:00
Alex Lam S.L
fdc10086da fix corner case in reduce_vars (#3667)
fixes #3666
2020-01-03 19:28:47 +08:00
Alex Lam S.L
746f5f6c62 fix corner case in unused (#3665)
fixes #3664
2020-01-01 20:24:30 +08:00
Alex Lam S.L
d83d3d741a enhance unused (#3662) 2019-12-31 23:39:24 +08:00
Alex Lam S.L
99ac73a635 enhance booleans (#3661) 2019-12-31 13:10:05 +08:00
Alex Lam S.L
a2e4c2fd97 enhance evaluate (#3660) 2019-12-31 11:51:21 +08:00
Alex Lam S.L
94785e8e14 fix corner case in booleans (#3659)
fixes #3658
2019-12-31 09:57:35 +08:00
Alex Lam S.L
4dbdac9c31 enhance booleans (#3657) 2019-12-30 22:41:11 +08:00
Alex Lam S.L
78c8efd851 fix corner case in evaluate (#3656)
fixes #3655
2019-12-29 21:16:53 +08:00
Alex Lam S.L
af310ba2d0 fix corner case in evaluate (#3654)
fixes #3653
2019-12-29 02:50:57 +00:00
Alex Lam S.L
2f3930d1b9 fix corner case in collapse_vars (#3652)
fixes #3651
2019-12-29 00:57:59 +00:00
Alex Lam S.L
d1a78920d9 workaround firefox asm.js quirks (#3650)
fixes #3636
2019-12-28 23:14:53 +00:00
Alex Lam S.L
d9cd3d33c8 enhance evaluate (#3649) 2019-12-28 20:26:15 +00:00
Alex Lam S.L
22b47cdd63 improve unicode handling (#3648) 2019-12-28 18:06:51 +00:00
Alex Lam S.L
4cf612dc9f increase mocha default timeout (#3647)
closes #3640
2019-12-28 02:32:22 +00:00
Alex Lam S.L
a19d31dd33 fix corner case in unsafe (#3646) 2019-12-27 14:24:54 +00:00
Alex Lam S.L
01d6e0f223 v3.7.3 2019-12-27 06:11:29 +08:00
Alex Lam S.L
ab050e7a94 fix corner case in directives (#3645) 2019-12-25 00:55:39 +00:00
Alex Lam S.L
75aa6ef848 enhance conditionals (#3643) 2019-12-22 04:29:32 +00:00
Alex Lam S.L
519a00bd8a fix corner case in collapse_vars (#3642)
fixes #3641
2019-12-22 01:08:56 +00:00
Alex Lam S.L
3ff0feddee suppress false positives from fuzzer (#3638) 2019-12-16 17:32:47 +02:00
Alex Lam S.L
74396acc86 fix corner case in loops (#3635)
fixes #3634
2019-12-11 06:39:46 +08:00
Alex Lam S.L
036bca980c enhance loops (#3633) 2019-12-10 12:57:47 +00:00
Alex Lam S.L
18c2b1841b fix corner case in reduce_vars (#3632)
fixes #3631
2019-12-10 09:45:51 +00:00
Alex Lam S.L
fe19ab7c57 v3.7.2 2019-12-08 15:36:18 +00:00
Alex Lam S.L
9074f05129 fix corner case in collapse_vars (#3629)
fixes #3628
2019-12-05 05:08:37 +08:00
Alex Lam S.L
04fbb1f949 avoid collision with HTML comments (#3625)
fixes #3624
2019-12-05 02:43:25 +08:00
Alex Lam S.L
bf7e4ca1a3 fix corner case in collapse_vars (#3627)
fixes #3626
2019-12-05 00:59:57 +08:00
Alex Lam S.L
d68ddc31f9 fix corner case in reduce_vars (#3623)
fixes #3622
2019-12-04 20:24:55 +08:00
Alex Lam S.L
500e31e03b enhance collapse_vars (#3621) 2019-12-02 15:25:38 +08:00
Alex Lam S.L
bef856addb fix corner case in keep_fargs (#3620)
fixes #3619
2019-12-02 12:28:17 +08:00
Alex Lam S.L
9a6faf365b fix corner cases in keep_fargs & unused (#3618) 2019-12-02 06:43:54 +08:00
Alex Lam S.L
e915832a36 enhance unused (#3617) 2019-12-01 18:10:37 +08:00
Alex Lam S.L
0593892d6e enhance collapse_vars (#3616) 2019-12-01 02:31:04 +08:00
Alex Lam S.L
b866a23671 v3.7.1 2019-11-30 06:02:09 +08:00
Alex Lam S.L
1283d73853 fix corner case in parsing directives (#3615) 2019-11-29 18:57:29 +08:00
Alex Lam S.L
1b61a81b5d enhance collapse_vars (#3613) 2019-11-29 17:45:49 +08:00
Alex Lam S.L
5a88c30d65 enhance assignments (#3612) 2019-11-28 07:40:34 +08:00
Alex Lam S.L
168ae747ad enhance collapse_vars (#3611) 2019-11-28 03:57:10 +08:00
Alex Lam S.L
d4b7010678 fix corner case in unsafe_regexp (#3609) 2019-11-27 17:35:21 +08:00
Alex Lam S.L
e27493f3c2 fix corner case in inline (#3608) 2019-11-27 14:54:36 +08:00
Alex Lam S.L
292d1de363 use stable Node.js version for fuzzing (#3605) 2019-11-26 02:11:11 +08:00
Alex Lam S.L
6768e6578f inline functions with directives more effectively (#3604) 2019-11-26 01:51:04 +08:00
Alex Lam S.L
48a0f6fe41 enhance unsafe_math (#3603) 2019-11-25 21:14:13 +08:00
Alex Lam S.L
81caadb709 enhance collapse_vars (#3602) 2019-11-20 12:54:49 +08:00
Alex Lam S.L
d959e0b86f fix corner case in if_return (#3601)
fixes #3600
2019-11-19 15:45:20 +08:00
Alex Lam S.L
67278e76c8 fix corner case in unused (#3599)
fixes #3598
2019-11-19 04:26:41 +08:00
Alex Lam S.L
c289ba1139 fix corner case in collapse_vars (#3597)
fixes #3596
2019-11-19 02:30:52 +08:00
Alex Lam S.L
02cc4a0d03 v3.7.0 2019-11-18 20:21:07 +08:00
Alex Lam S.L
4e06e1ca34 fix corner case in inline (#3595) 2019-11-18 15:04:55 +08:00
Alex Lam S.L
644f65feca fix corner case in unsafe_math (#3594)
fixes #3593
2019-11-18 13:44:13 +08:00
Alex Lam S.L
8504a4ea0e fix corner case in reduce_funcs (#3592) 2019-11-17 11:19:42 +08:00
Alex Lam S.L
10c1a78772 fix corner case in collapse_vars (#3591) 2019-11-17 05:24:02 +08:00
Alex Lam S.L
a6a0319f1c compress empty for-in loops (#3590) 2019-11-17 02:36:42 +08:00
Alex Lam S.L
d1b2ecec27 refine precision limits on unsafe_math (#3589) 2019-11-17 01:16:42 +08:00
Alex Lam S.L
552be61c4d introduce eager evaluation (#3587) 2019-11-16 06:10:47 +08:00
Alex Lam S.L
dcfc4aca5b minor clean-ups (#3588) 2019-11-16 00:40:22 +08:00
Alex Lam S.L
4027f87717 migrate to GitHub Actions (#3586) 2019-11-14 10:48:32 +08:00
Alex Lam S.L
910799ca99 fix corner case in switches (#3585) 2019-11-14 02:29:55 +08:00
Alex Lam S.L
4bd36dc8da enhance unused (#3584) 2019-11-13 21:44:44 +08:00
Alex Lam S.L
ab15c40770 enhance switches (#3583) 2019-11-13 20:03:48 +08:00
Alex Lam S.L
fe65ce9658 fix corner case in collapse_vars (#3582)
fixes #3581
2019-11-13 16:45:16 +08:00
Alex Lam S.L
d6fd18d0b0 enhance evaluate & inline (#3580) 2019-11-13 04:17:09 +08:00
Alex Lam S.L
0d17c5b0fa v3.6.9 2019-11-12 22:50:52 +08:00
Alex Lam S.L
5b20bad4b3 fix corner case in dead_code (#3579)
fixes #3578
2019-11-12 05:16:14 +08:00
Alex Lam S.L
765a06340f enable cache on GitHub Actions (#3570) 2019-11-10 09:06:48 +08:00
Alex Lam S.L
5045e140b1 fix corner case in conditionals (#3577)
fixes #3576
2019-11-09 00:53:15 +08:00
Alex Lam S.L
10648c9af6 enhance dead_code (#3575) 2019-11-08 13:45:28 +08:00
Alex Lam S.L
87e67ec299 fix corner case in collapse_vars (#3574)
fixes #3573
2019-11-07 20:38:03 +08:00
Alex Lam S.L
61a0dad9fe v3.6.8 2019-11-06 13:52:58 +08:00
Alex Lam S.L
3e2c51a4da enhance collapse_vars (#3572) 2019-11-05 18:15:28 +08:00
Alex Lam S.L
0e29ad5eb9 fix corner case in evaluate (#3569) 2019-11-04 13:13:48 +08:00
Alex Lam S.L
0f2687ecfc v3.6.7 2019-11-02 13:32:05 +08:00
Alex Lam S.L
1c0defdc03 enhance unsafe evaluate (#3564) 2019-11-02 03:34:32 +08:00
Alex Lam S.L
dcbf2236c7 more tests for #3562 (#3565) 2019-11-02 03:34:20 +08:00
Alex Lam S.L
24bb288832 fix corner case in collapse_vars (#3563)
fixes #3562
2019-11-01 22:38:19 +08:00
Alex Lam S.L
6ad8e1081f v3.6.6 2019-11-01 13:40:03 +08:00
Alex Lam S.L
815eff1f7c enhance if_return (#3560) 2019-11-01 02:08:31 +08:00
Alex Lam S.L
1e9b576ee9 fix corner case in evaluate (#3559)
fixes #3558
2019-11-01 00:01:25 +08:00
Alex Lam S.L
3797458365 enhance conditionals (#3557) 2019-10-31 09:33:46 +08:00
Alex Lam S.L
1858c2018c enhance typeofs (#3556) 2019-10-31 08:00:04 +08:00
Alex Lam S.L
ec7f071272 fix corner case in dead_code (#3553)
fixes #3552
2019-10-30 14:21:22 +08:00
Alex Lam S.L
f1eb03f2c0 enhance dead_code (#3551) 2019-10-30 06:34:54 +08:00
Alex Lam S.L
0f4cfa877a fix corner case in comments (#3550) 2019-10-30 03:49:39 +08:00
Alex Lam S.L
1d5c2becbd enhance evaluate (#3549) 2019-10-29 19:51:55 +08:00
Alex Lam S.L
22a09ea7c5 fix corner case in unsafe_math (#3548)
fixes #3547
2019-10-29 17:06:57 +08:00
Alex Lam S.L
bad664c632 compress object literals (#3546) 2019-10-29 16:53:48 +08:00
Alex Lam S.L
8a191c0a84 v3.6.5 2019-10-29 12:55:28 +08:00
Alex Lam S.L
83fb8b4ca1 fix corner case in ie8 (#3543)
fixes #3542
2019-10-28 23:54:27 +08:00
Alex Lam S.L
f38e31bd1e fix corner case in evaluate (#3540)
fixes #3539
2019-10-28 19:56:42 +08:00
Alex Lam S.L
24e8b47977 improve ufuzz resilience (#3541) 2019-10-28 18:08:51 +08:00
Alex Lam S.L
95618793a4 fix corner case in ufuzz (#3538) 2019-10-28 16:04:07 +08:00
Alex Lam S.L
2f3b460212 fix & enhance unsafe_math (#3537)
closes #3535
fixes #3536
2019-10-28 13:37:08 +08:00
Alex Lam S.L
06e135e35f migrate CI workaround (#3534) 2019-10-27 17:29:54 +08:00
Alex Lam S.L
ebbf3d4a51 improve ufuzz resilience (#3533) 2019-10-27 14:17:35 +08:00
Alex Lam S.L
a270ba6b59 fix corner cases in unsafe_math (#3532)
fixes #3531
2019-10-27 08:25:11 +08:00
Alex Lam S.L
37f35e4ac2 prevent tty truncation in test/compress (#3530) 2019-10-27 05:00:21 +08:00
Alex Lam S.L
50a578c1f6 compress arithmetic expressions further (#3529) 2019-10-27 03:07:07 +08:00
Alex Lam S.L
85237b08d4 fix corner case in collapse_vars (#3527)
fixes #3526
2019-10-26 05:41:02 +08:00
Alex Lam S.L
27b159e711 separate ufuzz job failures (#3525) 2019-10-25 02:06:29 +08:00
Alex Lam S.L
82b3eed5ef fix corner case in ie8 & mangle (#3524)
fixes #3523
2019-10-24 23:43:19 +08:00
Alex Lam S.L
0f7aa41e33 fix corner case in collapse_vars (#3521)
fixes #3520
2019-10-24 01:13:57 +08:00
Alex Lam S.L
370c8e0385 v3.6.4 2019-10-23 15:38:05 +08:00
Alex Lam S.L
4240fba9b8 fix corner cases in unused (#3519) 2019-10-23 06:46:05 +08:00
Alex Lam S.L
267bc70d33 fix corner case in unused (#3517)
fixes #3515
2019-10-23 01:58:40 +08:00
Alex Lam S.L
a53ab99378 fix corner case in side_effects (#3514)
fixes #3512
2019-10-23 01:04:00 +08:00
Alex Lam S.L
02308a7b56 fix corner case in reduce_vars (#3510)
fixes #3509
2019-10-22 20:36:05 +08:00
Alex Lam S.L
0b3705e82f fix corner cases in inline (#3507)
fixes #3506
2019-10-22 15:41:55 +08:00
Alex Lam S.L
da5a21b240 fix GitHub Actions script for fuzzing (#3504) 2019-10-21 04:30:00 +08:00
Alex Lam S.L
5bd0cf8633 enable GitHub Actions (#3503) 2019-10-21 04:11:14 +08:00
Alex Lam S.L
9199ab5846 minor tweaks (#3502) 2019-10-20 15:19:19 +08:00
Alex Lam S.L
ca6dce43fe fix corner case in collapse_vars (#3501) 2019-10-20 03:53:20 +08:00
Alex Lam S.L
543dd7d3d7 fix corner case in comments (#3500) 2019-10-20 03:21:30 +08:00
Alex Lam S.L
6b4886c908 v3.6.3 2019-10-19 14:28:11 +08:00
Alex Lam S.L
0201cb4b52 fix corner case in unused (#3499)
fixes #3497
2019-10-18 20:08:05 +08:00
Alex Lam S.L
cd072317d0 fix corner case in unused (#3496)
fixes #3495
2019-10-18 17:09:43 +08:00
Alex Lam S.L
0785a15ace fix corner case in dead_code & ie8 (#3494)
fixes #3493
2019-10-17 09:58:05 +08:00
Alex Lam S.L
b1279a46d9 fix corner case in sequences (#3491)
fixes #3490
2019-10-17 09:57:50 +08:00
Alex Lam S.L
b571619d31 handle throw of non-Errors gracefully (#3492) 2019-10-17 06:29:02 +08:00
Alex Lam S.L
7b5350b459 tweak Travis CI execution environment (#3489) 2019-10-16 15:47:06 +08:00
Alex Lam S.L
1549db70e6 fix corner case in ie8 (#3487)
fixes #3486
2019-10-16 12:18:27 +08:00
Alex Lam S.L
8ff9a3c8fb fix corner cases in ie8 (#3485)
fixes #3484
2019-10-16 06:37:40 +08:00
Alex Lam S.L
91cae51d8f fix corner case in evaluate & ie8 (#3483)
fixes #3482
2019-10-16 01:09:16 +08:00
Alex Lam S.L
8af2f5fbcf fix corner case in rename (#3481)
fixes #3480
2019-10-15 19:44:07 +08:00
Alex Lam S.L
86a8016323 fix corner case in ie8 & mangle (#3479)
fixes #3478
2019-10-15 17:14:48 +08:00
David xu
009dcdae01 avoid mangling of MutationObserver properties (#3477) 2019-10-15 16:16:43 +08:00
Alex Lam S.L
f86f615d83 fix corner case in ie8 & mangle (#3476)
fixes #3475
2019-10-15 14:18:12 +08:00
Alex Lam S.L
d3d1d11926 fix corner case in ie8 & rename (#3474)
fixes #3473
2019-10-15 07:27:02 +08:00
Alex Lam S.L
736019b767 fix corner cases in ie8 (#3472)
fixes #3471
2019-10-14 18:15:40 +08:00
Alex Lam S.L
a39bdb5840 fix corner case with collapse_vars & ie8 (#3469)
fixes #3468
2019-10-14 13:34:35 +08:00
Alex Lam S.L
e8ab0a44b2 update dependency (#3470) 2019-10-14 13:34:22 +08:00
Alex Lam S.L
c3ca293e6b v3.6.2 2019-10-12 20:19:05 +08:00
Alex Lam S.L
516b67a43b minor tweaks to CI test scripts (#3467) 2019-10-12 05:36:38 +08:00
Alex Lam S.L
eba3a37bb5 fix boolean context detection (#3466)
fixes #3465
2019-10-12 03:42:57 +08:00
Alex Lam S.L
6d57ca1a59 improve source map handling (#3464)
fixes #2947
fixes #3277
fixes #3411
2019-10-11 03:52:33 +08:00
Alex Lam S.L
3320251b4b update benchmark URLs (#3462) 2019-10-11 01:00:09 +08:00
Alex Lam S.L
33c94d3bd9 detect boolean context across IIFEs (#3461) 2019-10-10 09:37:02 +08:00
Alex Lam S.L
b18f717b46 improve readability of --help ast (#3460) 2019-10-10 04:32:32 +08:00
Alex Lam S.L
a0d4b648bb remove extraneous property (#3459)
fixes #3455
2019-10-10 01:36:58 +08:00
Alex Lam S.L
6db880e16d clean up AST_Binary optimisation logic (#3458) 2019-10-09 23:45:41 +08:00
98 changed files with 13457 additions and 2558 deletions

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

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

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

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

View File

@@ -1,46 +0,0 @@
cache:
directories: tmp
language: generic
matrix:
fast_finish: true
env:
- NODE=0.10 TYPE=compress
- NODE=0.10 TYPE=mocha
- NODE=0.10 TYPE=release/benchmark
- NODE=0.10 TYPE=release/jetstream
- NODE=0.12 TYPE=compress
- NODE=0.12 TYPE=mocha
- NODE=0.12 TYPE=release/benchmark
- NODE=0.12 TYPE=release/jetstream
- NODE=4 TYPE=compress
- NODE=4 TYPE=mocha
- NODE=4 TYPE=release/benchmark
- NODE=4 TYPE=release/jetstream
- NODE=6 TYPE=compress
- NODE=6 TYPE=mocha
- NODE=6 TYPE=release/benchmark
- NODE=6 TYPE=release/jetstream
- NODE=8 TYPE=compress
- NODE=8 TYPE=mocha
- NODE=8 TYPE=release/benchmark
- NODE=8 TYPE=release/jetstream
- NODE=10 TYPE=compress
- NODE=10 TYPE=mocha
- NODE=10 TYPE=release/benchmark
- NODE=10 TYPE=release/jetstream
- NODE=latest TYPE=compress
- NODE=latest TYPE=mocha
- NODE=latest TYPE=release/benchmark
- NODE=latest TYPE=release/jetstream
before_install:
- git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
- . ~/.nvs/nvs.sh
- nvs --version
install:
- nvs add node/$NODE
- nvs use node/$NODE
- node --version
- npm --version --no-update-notifier
- npm install --no-audit --no-optional --no-save --no-update-notifier
script:
- node test/$TYPE

View File

@@ -87,6 +87,7 @@ a double dash to prevent input files being used as option arguments:
`wrap_iife` Wrap IIFEs in parenthesis. Note: you may
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.
@@ -478,42 +479,42 @@ 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.
- `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
of function names. Useful for code relying on `Function.prototype.name`.
- `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
@@ -631,7 +632,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
- `evaluate` (default: `true`) -- Evaluate expression for shorter constant
representation. Pass `"eager"` to always replace function calls whenever
possible, or a positive integer to specify an upper bound for each individual
evaluation in number of characters.
- `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
@@ -682,6 +686,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
where the return value is discarded, to avoid the parens that the
code generator would insert.
- `objects` (default: `true`) -- compact duplicate keys in object literals.
- `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.
@@ -730,6 +736,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
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
@@ -840,8 +848,14 @@ can pass additional arguments that control the code output:
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.
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`)

View File

@@ -1,74 +1,5 @@
build: off
cache:
- tmp
matrix:
fast_finish: true
environment:
matrix:
- NODE: 0.10
TYPE: compress
- NODE: 0.10
TYPE: mocha
- NODE: 0.10
TYPE: release/benchmark
- NODE: 0.10
TYPE: release/jetstream
- NODE: 0.12
TYPE: compress
- NODE: 0.12
TYPE: mocha
- NODE: 0.12
TYPE: release/benchmark
- NODE: 0.12
TYPE: release/jetstream
- NODE: 4
TYPE: compress
- NODE: 4
TYPE: mocha
- NODE: 4
TYPE: release/benchmark
- NODE: 4
TYPE: release/jetstream
- NODE: 6
TYPE: compress
- NODE: 6
TYPE: mocha
- NODE: 6
TYPE: release/benchmark
- NODE: 6
TYPE: release/jetstream
- NODE: 8
TYPE: compress
- NODE: 8
TYPE: mocha
- NODE: 8
TYPE: release/benchmark
- NODE: 8
TYPE: release/jetstream
- NODE: 10
TYPE: compress
- NODE: 10
TYPE: mocha
- NODE: 10
TYPE: release/benchmark
- NODE: 10
TYPE: release/jetstream
- NODE: latest
TYPE: compress
- NODE: latest
TYPE: mocha
- NODE: latest
TYPE: release/benchmark
- NODE: latest
TYPE: release/jetstream
install:
- git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git %LOCALAPPDATA%\nvs
- set PATH=%LOCALAPPDATA%\nvs;%PATH%
- nvs --version
- nvs add node/%NODE%
- nvs use node/%NODE%
- node --version
- npm --version --no-update-notifier
- npm install --no-audit --no-optional --no-save --no-update-notifier
test_script:
- node test/%TYPE%
- echo No longer in use

View File

@@ -36,6 +36,7 @@ program.option("-c, --compress [options]", "Enable compressor/specify compressor
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.");
@@ -53,13 +54,14 @@ 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
}).getValue();
}).value;
}
}
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
@@ -93,6 +95,10 @@ if (program.beautify) {
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";
@@ -210,7 +216,15 @@ 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") {
@@ -323,7 +337,7 @@ function simple_glob(glob) {
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.filter(function(name) {
var results = entries.sort().filter(function(name) {
return rx.test(name);
}).map(function(name) {
return path.join(dir, name);
@@ -370,7 +384,7 @@ function parse_js(flag) {
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
});
}

View File

@@ -169,10 +169,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
}, AST_Statement);
function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Statement) {
body._walk(visitor);
} else body.forEach(function(node) {
node.body.forEach(function(node) {
node._walk(visitor);
});
}
@@ -351,7 +348,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
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);
}
}));
},
@@ -370,7 +367,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
filename: "enclose=" + JSON.stringify(args_values)
}).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body);
return List.splice(body);
}
}));
}
@@ -618,7 +615,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
getProperty: function() {
var p = this.property;
if (p instanceof AST_Constant) {
return p.getValue();
return p.value;
}
if (p instanceof AST_UnaryPrefix
&& p.operator == "void"
@@ -824,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", {
@@ -837,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);
@@ -968,11 +961,13 @@ TreeWalker.prototype = {
in_boolean_context: function() {
var self = this.self();
for (var i = 0, p; p = this.parent(i); i++) {
if (p instanceof AST_SimpleStatement
|| p instanceof AST_Conditional && p.condition === self
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;
}
@@ -980,6 +975,15 @@ TreeWalker.prototype = {
|| 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,39 @@
"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(name, code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(\S+)\s*$/.exec(code);
if (!match) {
AST_Node.warn("inline source map not found: " + name);
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]);
}
}
return to_ascii(match[2]);
AST_Node.warn("inline source map not found: " + name);
}
function parse_source_map(content) {
@@ -134,10 +154,10 @@ function minify(files, options) {
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);
options.parse.toplevel = toplevel = parse(files[name], options.parse);
if (source_maps) {
if (source_map_content == "inline") {
var inlined_content = read_source_map(name, files[name]);
var inlined_content = read_source_map(name, toplevel);
if (inlined_content) {
source_maps[name] = parse_source_map(inlined_content);
}
@@ -146,7 +166,6 @@ function minify(files, options) {
}
}
}
toplevel = options.parse.toplevel;
}
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
@@ -184,6 +203,7 @@ function minify(files, options) {
if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) {
options.output.source_map = SourceMap({
content: options.sourceMap.includeSources,
file: options.sourceMap.filename,
orig: source_maps,
root: options.sourceMap.root
@@ -192,10 +212,8 @@ function minify(files, options) {
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]);
}
} else {
options.output.source_map.get()._sourcesContents = null;
}
}
delete options.output.ast;
@@ -233,7 +251,7 @@ function minify(files, options) {
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;

View File

@@ -403,7 +403,7 @@
var def = M.definition();
return {
type: "Identifier",
name: def ? def.mangled_name || def.name : M.name
name: def && def.mangled_name || M.name
};
});

View File

@@ -43,8 +43,6 @@
"use strict";
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
function is_some_comments(comment) {
// multiline comment
return comment.type == "comment2" && /@preserve|@license|@cc_on/i.test(comment.value);
@@ -91,13 +89,11 @@ function OutputStream(options) {
comment_filter = function(comment) {
return comment.type != "comment5" && comments.test(comment.value);
};
}
else if (typeof comments === "function") {
} else if (typeof comments === "function") {
comment_filter = function(comment) {
return comment.type != "comment5" && comments(this, comment);
};
}
else if (comments === "some") {
} else if (comments === "some") {
comment_filter = is_some_comments;
} else { // NOTE includes "all" option
comment_filter = return_true;
@@ -123,15 +119,20 @@ function OutputStream(options) {
});
} : function(str) {
var s = "";
for (var i = 0; i < str.length; i++) {
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
s += "\\u" + str.charCodeAt(i).toString(16);
} else {
s += str[i];
for (var i = 0, j = 0; i < str.length; i++) {
var code = str.charCodeAt(i);
if (is_surrogate_pair_head(code)) {
if (is_surrogate_pair_tail(str.charCodeAt(i + 1))) {
i++;
continue;
}
} else if (!is_surrogate_pair_tail(code)) {
continue;
}
s += str.slice(j, i) + "\\u" + code.toString(16);
j = i + 1;
}
return s;
return j == 0 ? str : s + str.slice(j);
};
function make_string(str, quote) {
@@ -271,7 +272,7 @@ function OutputStream(options) {
}
}
newline_insert = -1;
var prev = last.charAt(last.length - 1);
var prev = last.slice(-1);
if (might_need_semicolon) {
might_need_semicolon = false;
@@ -300,16 +301,16 @@ function OutputStream(options) {
}
if (might_need_space) {
if ((is_identifier_char(prev)
&& (is_identifier_char(ch) || ch == "\\"))
if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")
|| (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last))
{
|| ((ch == "+" || ch == "-") && ch == last)
|| str == "--" && last == "!"
|| last == "--" && ch == ">") {
OUTPUT += " ";
current_col++;
current_pos++;
}
might_need_space = false;
if (prev != "<" || str != "!") might_need_space = false;
}
if (mapping_token) {
@@ -324,7 +325,7 @@ function OutputStream(options) {
}
OUTPUT += str;
has_parens = str[str.length - 1] == "(";
has_parens = str.slice(-1) == "(";
current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n;
@@ -380,7 +381,7 @@ function OutputStream(options) {
};
function force_semicolon() {
might_need_semicolon = false;
if (might_need_semicolon) print(";");
print(";");
}
@@ -452,7 +453,7 @@ function OutputStream(options) {
var self = this;
var scan = node instanceof AST_Exit && node.value;
var comments = dump(node);
if (!comments) return;
if (!comments) comments = [];
if (scan) {
var tw = new TreeWalker(function(node) {
@@ -587,17 +588,7 @@ function OutputStream(options) {
force_semicolon : force_semicolon,
to_utf8 : to_utf8,
print_name : function(name) { print(make_name(name)) },
print_string : function(str, quote, escape_directive) {
var encoded = encode_string(str, quote);
if (escape_directive === true && encoded.indexOf("\\") === -1) {
// Insert semicolons to break directive prologue
if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
force_semicolon();
}
force_semicolon();
}
print(encoded);
},
print_string : function(str, quote) { print(encode_string(str, quote)) },
next_indent : next_indent,
with_indent : with_indent,
with_block : with_block,
@@ -635,18 +626,10 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator);
}
var in_directive = false;
var active_scope = null;
var use_asm = null;
var use_asm = false;
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
}
function doit() {
stream.prepend_comments(self);
self.add_source_map(stream);
@@ -660,9 +643,6 @@ function OutputStream(options) {
doit();
}
stream.pop_node();
if (self === use_asm) {
use_asm = null;
}
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
@@ -714,16 +694,23 @@ function OutputStream(options) {
PARENS(AST_Sequence, function(output) {
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
* ==> 20 (side effect, set a := 10 and b := 20) */
;
// (foo, bar)() or foo(1, (2, 3), 4)
return p instanceof AST_Call
// !(foo, bar, baz)
|| p instanceof AST_Unary
// 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_Binary
// var a = (1, 2), b = a + a; ==> b == 4
|| p instanceof AST_VarDef
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|| p instanceof AST_PropAccess && p.expression === this
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|| p instanceof AST_Array
// { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_ObjectProperty
// (false, true) ? (a = 10, b = 20) : (c = 30)
// ==> 20 (side effect, set a := 10 and b := 20)
|| p instanceof AST_Conditional;
});
PARENS(AST_Binary, function(output) {
@@ -795,7 +782,9 @@ function OutputStream(options) {
PARENS(AST_Number, function(output) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) {
var value = this.getValue();
var value = this.value;
// https://github.com/mishoo/UglifyJS2/issues/115
// https://github.com/mishoo/UglifyJS2/pull/1009
if (value < 0 || /^0/.test(make_num(value))) {
return true;
}
@@ -824,7 +813,18 @@ function OutputStream(options) {
/* -----[ PRINTERS ]----- */
DEFPRINT(AST_Directive, function(self, output) {
output.print_string(self.value, self.quote);
var quote = self.quote;
var value = self.value;
switch (output.option("quote_style")) {
case 0:
case 2:
if (value.indexOf('"') == -1) quote = '"';
break;
case 1:
if (value.indexOf("'") == -1) quote = "'";
break;
}
output.print(quote + value + quote);
output.semicolon();
});
DEFPRINT(AST_Debugger, function(self, output) {
@@ -836,30 +836,27 @@ function OutputStream(options) {
function display_body(body, is_toplevel, output, allow_directives) {
var last = body.length - 1;
in_directive = allow_directives;
var in_directive = allow_directives;
var was_asm = use_asm;
body.forEach(function(stmt, i) {
if (in_directive === true && !(stmt instanceof AST_Directive ||
stmt instanceof AST_EmptyStatement ||
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
)) {
in_directive = false;
}
if (!(stmt instanceof AST_EmptyStatement)) {
output.indent();
stmt.print(output);
if (!(i == last && is_toplevel)) {
output.newline();
if (is_toplevel) output.newline();
if (in_directive) {
if (stmt instanceof AST_Directive) {
if (stmt.value == "use asm") use_asm = true;
} else if (!(stmt instanceof AST_EmptyStatement)) {
if (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String) {
output.force_semicolon();
}
in_directive = false;
}
}
if (in_directive === true &&
stmt instanceof AST_SimpleStatement &&
stmt.body instanceof AST_String
) {
in_directive = false;
}
if (stmt instanceof AST_EmptyStatement) return;
output.indent();
stmt.print(output);
if (i == last && is_toplevel) return;
output.newline();
if (is_toplevel) output.newline();
});
in_directive = false;
use_asm = was_asm;
}
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
@@ -1043,11 +1040,9 @@ function OutputStream(options) {
return;
}
b = b.alternative;
}
else if (b instanceof AST_StatementWithBody) {
} else if (b instanceof AST_StatementWithBody) {
b = b.body;
}
else break;
} else break;
}
force_statement(self.body, output);
}
@@ -1219,7 +1214,7 @@ function OutputStream(options) {
output.print_string(prop);
output.print("]");
} else {
if (expr instanceof AST_Number && expr.getValue() >= 0) {
if (expr instanceof AST_Number && expr.value >= 0) {
if (!/[xa-f.)]/i.test(output.last())) {
output.print(".");
}
@@ -1252,29 +1247,10 @@ function OutputStream(options) {
output.print(self.operator);
});
DEFPRINT(AST_Binary, function(self, output) {
var op = self.operator;
self.left.print(output);
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
&& self.left instanceof AST_UnaryPostfix
&& self.left.operator == "--") {
// space is mandatory to avoid outputting -->
output.print(" ");
} else {
// the space is optional depending on "beautify"
output.space();
}
output.print(op);
if ((op == "<" || op == "<<")
&& self.right instanceof AST_UnaryPrefix
&& self.right.operator == "!"
&& self.right.expression instanceof AST_UnaryPrefix
&& self.right.expression.operator == "--") {
// space is mandatory to avoid outputting <!--
output.print(" ");
} else {
// the space is optional depending on "beautify"
output.space();
}
output.space();
output.print(self.operator);
output.space();
self.right.print(output);
});
DEFPRINT(AST_Conditional, function(self, output) {
@@ -1355,34 +1331,41 @@ function OutputStream(options) {
});
DEFPRINT(AST_Symbol, function(self, output) {
var def = self.definition();
output.print_name(def ? def.mangled_name || def.name : self.name);
output.print_name(def && def.mangled_name || self.name);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output) {
output.print("this");
});
DEFPRINT(AST_Constant, function(self, output) {
output.print(self.getValue());
output.print(self.value);
});
DEFPRINT(AST_String, function(self, output) {
output.print_string(self.getValue(), self.quote, in_directive);
output.print_string(self.value, self.quote);
});
DEFPRINT(AST_Number, function(self, output) {
if (use_asm && self.start && self.start.raw != null) {
output.print(self.start.raw);
} else {
output.print(make_num(self.getValue()));
output.print(make_num(self.value));
}
});
DEFPRINT(AST_RegExp, function(self, output) {
var regexp = self.getValue();
var regexp = self.value;
var str = regexp.toString();
var end = str.lastIndexOf("/");
if (regexp.raw_source) {
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
str = "/" + regexp.raw_source + str.slice(end);
} else if (end == 1) {
str = "/(?:)" + str.slice(end);
} else if (str.indexOf("/", 1) < end) {
str = "/" + str.slice(1, end).replace(/\\\\|[^/]?\//g, function(match) {
return match[0] == "\\" ? match : match.slice(0, -1) + "\\/";
}) + str.slice(end);
}
output.print(output.to_utf8(str).replace(/\\(?:\0(?![0-9])|[^\0])/g, function(seq) {
switch (seq[1]) {
output.print(output.to_utf8(str).replace(/\\(?:\0(?![0-9])|[^\0])/g, function(match) {
switch (match[1]) {
case "\n": return "\\n";
case "\r": return "\\r";
case "\t": return "\t";
@@ -1392,7 +1375,7 @@ function OutputStream(options) {
case "\x0B": return "\v";
case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029";
default: return seq;
default: return match;
}
}).replace(/[\n\r\u2028\u2029]/g, function(c) {
switch (c) {

View File

@@ -133,14 +133,10 @@ function is_letter(code) {
}
function is_surrogate_pair_head(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xd800 && code <= 0xdbff;
}
function is_surrogate_pair_tail(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xdc00 && code <= 0xdfff;
}
@@ -234,6 +230,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
directives : {},
directive_stack : []
};
var prev_was_dot = false;
function peek() {
return S.text.charAt(S.pos);
@@ -244,16 +241,16 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (signal_eof && !ch)
throw EX_EOF;
if (NEWLINE_CHARS[ch]) {
S.newline_before = S.newline_before || !in_string;
++S.line;
S.col = 0;
if (!in_string && ch == "\r" && peek() == "\n") {
// treat a \r\n sequence as a single \n
++S.pos;
S.line++;
if (!in_string) S.newline_before = true;
if (ch == "\r" && peek() == "\n") {
// treat `\r\n` as `\n`
S.pos++;
ch = "\n";
}
} else {
++S.col;
S.col++;
}
return ch;
}
@@ -286,16 +283,12 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
S.tokpos = S.pos;
}
var prev_was_dot = false;
function token(type, value, is_comment) {
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX[value]) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION[value]));
if (type == "punc" && value == ".") {
prev_was_dot = true;
} else if (!is_comment) {
prev_was_dot = false;
}
S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value]
|| type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]
|| type == "punc" && PUNC_BEFORE_EXPRESSION[value];
if (type == "punc" && value == ".") prev_was_dot = true;
else if (!is_comment) prev_was_dot = false;
var ret = {
type : type,
value : value,
@@ -358,11 +351,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
parse_error("Legacy octal literals are not allowed in strict mode");
}
var valid = parse_js_number(num);
if (!isNaN(valid)) {
return token("num", valid);
} else {
parse_error("Invalid syntax: " + num);
}
if (!isNaN(valid)) return token("num", valid);
parse_error("Invalid syntax: " + num);
}
function read_escaped_char(in_string) {
@@ -463,8 +453,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (ch == "\\") escaped = backslash = true, next();
else if (is_identifier_char(ch)) name += next();
else break;
}
else {
} else {
if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
ch = read_escaped_char();
if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
@@ -538,9 +527,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function handle_dot() {
next();
return is_digit(peek().charCodeAt(0))
? read_num(".")
: token("punc", ".");
return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
}
function read_word() {
@@ -592,11 +579,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
switch (code) {
case 34: case 39: return read_string(ch);
case 46: return handle_dot();
case 47: {
var tok = handle_slash();
if (tok === next_token) continue;
return tok;
}
case 47:
var tok = handle_slash();
if (tok === next_token) continue;
return tok;
}
if (is_digit(code)) return read_num();
if (PUNC_CHARS[ch]) return token("punc", next());
@@ -614,12 +600,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
next_token.add_directive = function(directive) {
S.directive_stack[S.directive_stack.length - 1].push(directive);
if (S.directives[directive] === undefined) {
S.directives[directive] = 1;
} else {
S.directives[directive]++;
}
if (S.directives[directive]) S.directives[directive]++;
else S.directives[directive] = 1;
}
next_token.push_directives_stack = function() {
@@ -627,13 +609,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
next_token.pop_directives_stack = function() {
var directives = S.directive_stack[S.directive_stack.length - 1];
for (var i = 0; i < directives.length; i++) {
var directives = S.directive_stack.pop();
for (var i = directives.length; --i >= 0;) {
S.directives[directives[i]]--;
}
S.directive_stack.pop();
}
next_token.has_directive = function(directive) {
@@ -645,27 +624,17 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
/* -----[ Parser (constants) ]----- */
var UNARY_PREFIX = makePredicate([
"typeof",
"void",
"delete",
"--",
"++",
"!",
"~",
"-",
"+"
]);
var UNARY_PREFIX = makePredicate("typeof void delete -- ++ ! ~ - +");
var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
var UNARY_POSTFIX = makePredicate("-- ++");
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
var ASSIGNMENT = makePredicate("= += -= /= *= %= >>= <<= >>>= |= ^= &=");
var PRECEDENCE = function(a, ret) {
for (var i = 0; i < a.length; ++i) {
var b = a[i];
for (var j = 0; j < b.length; ++j) {
ret[b[j]] = i + 1;
for (var i = 0; i < a.length;) {
var b = a[i++];
for (var j = 0; j < b.length; j++) {
ret[b[j]] = i;
}
}
return ret;
@@ -682,7 +651,7 @@ var PRECEDENCE = function(a, ret) {
["*", "/", "%"]
], {});
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]);
var ATOMIC_START_TOKEN = makePredicate("atom num string regexp name");
/* -----[ Parser ]----- */
@@ -698,10 +667,9 @@ function parse($TEXT, options) {
}, true);
var S = {
input : (typeof $TEXT == "string"
? tokenizer($TEXT, options.filename,
options.html5_comments, options.shebang)
: $TEXT),
input : typeof $TEXT == "string"
? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
: $TEXT,
token : null,
prev : null,
peeked : null,
@@ -757,15 +725,12 @@ function parse($TEXT, options) {
}
function unexpected(token) {
if (token == null)
token = S.token;
if (token == null) token = S.token;
token_error(token, "Unexpected token: " + token_to_string(token.type, token.value));
}
function expect_token(type, val) {
if (is(type, val)) {
return next();
}
if (is(type, val)) return next();
token_error(S.token, "Unexpected token: " + token_to_string(S.token.type, S.token.value) + ", expected: " + token_to_string(type, val));
}
@@ -818,20 +783,19 @@ function parse($TEXT, options) {
handle_regexp();
switch (S.token.type) {
case "string":
if (S.in_directives) {
var token = peek();
if (S.token.raw.indexOf("\\") == -1
&& (is_token(token, "punc", ";")
|| is_token(token, "punc", "}")
|| has_newline_before(token)
|| is_token(token, "eof"))) {
S.input.add_directive(S.token.value);
var dir = S.in_directives;
var body = expression(true);
if (dir) {
if (body instanceof AST_String) {
var value = body.start.raw.slice(1, -1);
S.input.add_directive(value);
body.value = value;
} else {
S.in_directives = false;
S.in_directives = dir = false;
}
}
var dir = S.in_directives, stat = simple_statement();
return dir ? new AST_Directive(stat.body) : stat;
semicolon();
return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
case "num":
case "regexp":
case "operator":
@@ -996,8 +960,10 @@ function parse($TEXT, options) {
return new AST_LabeledStatement({ body: stat, label: label });
}
function simple_statement(tmp) {
return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
function simple_statement() {
var body = expression(true);
semicolon();
return new AST_SimpleStatement({ body: body });
}
function break_cont(type) {
@@ -1284,6 +1250,7 @@ function parse($TEXT, options) {
var ex = expression(true);
var len = start.comments_before.length;
[].unshift.apply(ex.start.comments_before, start.comments_before);
start.comments_before.length = 0;
start.comments_before = ex.start.comments_before;
start.comments_before_length = len;
if (len == 0 && start.comments_before.length > 0) {
@@ -1299,6 +1266,7 @@ function parse($TEXT, options) {
var end = prev();
end.comments_before = ex.end.comments_before;
[].push.apply(ex.end.comments_after, end.comments_after);
end.comments_after.length = 0;
end.comments_after = ex.end.comments_after;
ex.end = end;
if (ex instanceof AST_Call) mark_pure(ex);

View File

@@ -55,6 +55,7 @@ function SymbolDef(scope, orig, init) {
this.mangled_name = null;
this.undeclared = false;
this.id = SymbolDef.next_id++;
this.lambda = orig instanceof AST_SymbolLambda;
}
SymbolDef.next_id = 1;
@@ -161,17 +162,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
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;
@@ -191,13 +197,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// pass 3: fix up any scoping issue with IE8
if (options.ie8) self.walk(new TreeWalker(function(node) {
if (node instanceof AST_SymbolCatch) {
redefine(node, node.thedef.defun);
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);
node.thedef.init = def.init;
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;
}
}));
@@ -205,11 +219,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
function redefine(node, scope) {
var name = node.name;
var old_def = node.thedef;
var new_def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
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);
}
});
@@ -281,9 +308,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
def.init = init;
}
if (def.init instanceof AST_Function) def.init = init;
} else {
def = new SymbolDef(this, symbol, init);
this.variables.set(symbol.name, def);
@@ -413,7 +438,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
if (options.cache && node instanceof AST_Toplevel) {
node.globals.each(mangle);
}
node.variables.each(mangle);
if (node instanceof AST_Defun && tw.has_directive("use asm")) {
var sym = new AST_SymbolRef(node.name);
sym.scope = node;
sym.reference(options);
}
node.variables.each(function(def) {
if (!defer_redef(def)) mangle(def);
});
return true;
}
if (node instanceof AST_Label) {
@@ -426,22 +458,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
}
if (!options.ie8 && node instanceof AST_Catch) {
var def = node.argname.definition();
var redef = def.redefined();
if (redef) {
redefined.push(def);
reference(node.argname);
def.references.forEach(reference);
}
var redef = defer_redef(def, node.argname);
descend();
if (!redef) mangle(def);
return true;
}
function reference(sym) {
sym.thedef = redef;
sym.reference(options);
sym.thedef = def;
}
});
this.walk(tw);
redefined.forEach(mangle);
@@ -450,6 +471,21 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
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("find_colliding_names", function(options) {
@@ -499,13 +535,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
if (def.global && options.cache) return;
if (def.unmangleable(options)) return;
if (options.reserved.has[def.name]) return;
var d = def.redefined();
def.name = d ? d.name : next_name();
var redef = def.redefined();
var name = redef ? redef.rename || redef.name : next_name();
def.rename = name;
def.orig.forEach(function(sym) {
sym.name = def.name;
sym.name = name;
});
def.references.forEach(function(sym) {
sym.name = def.name;
sym.name = name;
});
}
});

View File

@@ -43,62 +43,148 @@
"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, {
content: false,
file: null,
root: null,
orig: null,
orig_line_diff: 0,
dest_line_diff: 0,
}, true);
var generator = new MOZ_SourceMap.SourceMapGenerator({
file: options.file,
sourceRoot: options.root
});
var maps = options.orig && Object.create(null);
if (maps) for (var source in options.orig) {
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
if (Array.isArray(options.orig[source].sources)) {
map._sources.toArray().forEach(function(source) {
var sourceContent = map.sourceContentFor(source, true);
if (sourceContent) generator.setSourceContent(source, sourceContent);
});
}
maps[source] = map;
}
return {
add: function(source, gen_line, gen_col, orig_line, orig_col, name) {
var map = maps && maps[source];
if (map) {
var info = map.originalPositionFor({
line: orig_line,
column: orig_col
var sources = create_array_map();
var sources_content = options.content && Object.create(null);
var names = create_array_map();
var mappings = "";
if (options.orig) Object.keys(options.orig).forEach(function(name) {
var map = options.orig[name];
var indices = [ 0, 0, 1, 0, 0 ];
options.orig[name] = {
names: map.names,
mappings: map.mappings.split(/;/).map(function(line) {
indices[0] = 0;
return line.split(/,/).map(function(segment) {
return indices.slice(0, vlq_decode(indices, segment));
});
if (info.source === null) return;
source = info.source;
orig_line = info.line;
orig_col = info.column;
name = info.name || name;
}
generator.addMapping({
name: name,
source: source,
generated: {
line: gen_line + options.dest_line_diff,
column: gen_col
},
original: {
line: orig_line + options.orig_line_diff,
column: orig_col
}),
sources: map.sources,
};
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;
}
});
},
get: function() {
return generator;
},
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(generator.toJSON());
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 (generated_line < gen_line) {
generated_column = 0;
do {
mappings += ";";
} while (++generated_line < gen_line);
} else if (mappings) {
mappings += ",";
}
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

@@ -52,7 +52,7 @@ TreeTransformer.prototype = new TreeWalker;
(function(DEF) {
function do_list(list, tw) {
return MAP(list, function(node) {
return List(list, function(node) {
return node.transform(tw, true);
});
}

View File

@@ -113,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);
@@ -127,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 {
@@ -145,20 +144,19 @@ 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) {
@@ -187,7 +185,7 @@ function makePredicate(words) {
function all(array, predicate) {
for (var i = array.length; --i >= 0;)
if (!predicate(array[i]))
if (!predicate(array[i], i))
return false;
return true;
}
@@ -219,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));

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.6.1",
"version": "3.9.1",
"engines": {
"node": ">=0.8.0"
},
@@ -23,8 +23,7 @@
"LICENSE"
],
"dependencies": {
"commander": "2.20.0",
"source-map": "~0.6.1"
"commander": "~2.20.3"
},
"devDependencies": {
"acorn": "~7.1.0",

View File

@@ -5,23 +5,22 @@
var createHash = require("crypto").createHash;
var fetch = require("./fetch");
var fork = require("child_process").fork;
var spawn = require("child_process").spawn;
var zlib = require("zlib");
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc");
}
args.unshift("bin/uglifyjs");
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://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.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;
@@ -70,18 +69,20 @@ urls.forEach(function(url) {
};
fetch(url, function(err, res) {
if (err) throw err;
var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
var uglifyjs = spawn(process.argv[0], args, { silent: true });
res.on("data", function(data) {
results[url].input += data.length;
}).pipe(uglifyjs.stdin);
var sha1 = createHash("sha1");
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");
sha1.update(data);
}).on("end", function() {
results[url].sha1 = sha1.digest("hex");
done();
});
uglifyjs.stderr.setEncoding("utf8");

View File

@@ -1,3 +1,7 @@
"use strict";
require("../tools/exit");
var assert = require("assert");
var child_process = require("child_process");
var fs = require("fs");
@@ -9,7 +13,7 @@ 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.json").map(JSON.stringify);
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) {
@@ -203,8 +207,9 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
});
return false;
} else {
var expected = stdout[options.toplevel ? 1 : 0];
var actual = run_code(result.code, options.toplevel);
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;
}
@@ -374,7 +379,10 @@ function test_case(test) {
}
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 = test.options.toplevel;
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;

View File

@@ -16,6 +16,7 @@ holes_and_undefined: {
constant_join: {
options = {
evaluate: true,
strings: true,
unsafe: true,
}
input: {
@@ -65,6 +66,7 @@ constant_join: {
constant_join_2: {
options = {
evaluate: true,
strings: true,
unsafe: true,
}
input: {
@@ -94,9 +96,11 @@ constant_join_2: {
constant_join_3: {
options = {
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";

View File

@@ -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 };
@@ -166,3 +166,69 @@ asm_nested_functions: {
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}
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

@@ -290,26 +290,60 @@ increment_decrement_2: {
expect_stdout: "42"
}
issue_3375: {
issue_3375_1: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(typeof function(b) {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect: {
console.log(typeof function(b) {
function p(o) {
console.log(typeof o, o);
}
p(function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect_stdout: "string"
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: {

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -33,10 +33,10 @@ unsafe_comps: {
}
expect: {
var obj1, obj2;
obj2 < obj1 ? g1() : f1();
obj1 < obj2 ? f2() : g2();
obj1 < obj2 ? g3() : f3();
obj2 < obj1 ? f4() : g4();
(obj2 < obj1 ? g1 : f1)();
(obj1 < obj2 ? f2 : g2)();
(obj1 < obj2 ? g3 : f3)();
(obj2 < obj1 ? f4 : g4)();
}
}

View File

@@ -26,7 +26,9 @@ concat_1: {
}
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

@@ -41,7 +41,7 @@ ifs_2: {
}
expect: {
foo ? x() : bar ? y() : baz && z();
foo ? x() : bar ? y() : baz ? z() : t();
(foo ? x : bar ? y : baz ? z : t)();
}
}
@@ -161,6 +161,24 @@ 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,
@@ -271,11 +289,50 @@ 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,
@@ -645,6 +702,87 @@ cond_9: {
}
}
cond_10: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f(a) {
if (1 == a) return "foo";
if (2 == a) return "foo";
if (3 == a) return "foo";
if (4 == a) return 42;
if (5 == a) return "foo";
if (6 == a) return "foo";
return "bar";
}
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
}
expect: {
function f(a) {
return 1 == a || 2 == a || 3 == a ? "foo" : 4 == a ? 42 : 5 == a || 6 == a ? "foo" : "bar";
}
console.log(f(1), f(2), f(3), f(4), f(5), f(6), f(7));
}
expect_stdout: "foo foo foo 42 foo foo bar"
}
cond_11: {
options = {
conditionals: true,
}
input: {
var o = {
p: "foo",
q: function() {
return this.p;
}
};
function f() {
return "bar";
}
function g(a) {
return a ? f() : o.q();
}
console.log(g(0), g(1));
}
expect: {
var o = {
p: "foo",
q: function() {
return this.p;
}
};
function f() {
return "bar";
}
function g(a) {
return a ? f() : o.q();
}
console.log(g(0), g(1));
}
expect_stdout: "foo bar"
}
cond_12: {
options = {
conditionals: true,
}
input: {
x ? y && a : a;
x ? y || a : a;
x ? a : y && a;
x ? a : y || a;
}
expect: {
(!x || y) && a;
x && y || a;
(x || y) && a;
!x && y || a;
}
}
ternary_boolean_consequent: {
options = {
booleans: true,
@@ -1102,11 +1240,11 @@ issue_2535_1: {
expect: {
y();
x() && y();
(x(), 1) && y();
x(), y();
x() && y();
x() && y();
x() && y();
(x(), 0) && y();
x();
}
}
@@ -1471,3 +1609,60 @@ angularjs_chain: {
}
}
}
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

@@ -141,207 +141,6 @@ try_catch_finally: {
]
}
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}
collapse_vars_assignment: {
options = {
collapse_vars: true,
@@ -863,23 +662,6 @@ issue_2749: {
expect_stdout: "PASS"
}
unsafe_builtin: {
options = {
side_effects: true,
unsafe: true,
}
input: {
(!w).constructor(x);
Math.abs(y);
[ 1, 2, z ].valueOf();
}
expect: {
w, x;
y;
z;
}
}
issue_2860_1: {
options = {
dead_code: true,
@@ -892,9 +674,7 @@ issue_2860_1: {
}());
}
expect: {
console.log(function(a) {
return 1 ^ a;
}());
console.log(1);
}
expect_stdout: "1"
}
@@ -943,24 +723,6 @@ issue_2929: {
expect_stdout: "PASS"
}
unsafe_string_replace: {
options = {
side_effects: true,
unsafe: true,
}
input: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3402: {
options = {
dead_code: true,
@@ -1013,3 +775,120 @@ issue_3406: {
}
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"
}

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

@@ -699,18 +699,6 @@ iife: {
}
}
drop_value: {
options = {
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), bar();
}
}
issue_1539: {
options = {
collapse_vars: true,
@@ -1019,14 +1007,21 @@ delete_assign_1: {
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
expect_stdout: [
"true",
"true",
"true",
"true",
"true",
"true",
]
}
delete_assign_2: {
@@ -1047,14 +1042,21 @@ delete_assign_2: {
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((NaN, !0));
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
expect_stdout: [
"true",
"true",
"true",
"true",
"true",
"true",
]
}
drop_var: {
@@ -1189,10 +1191,10 @@ issue_2105_1: {
input: {
!function(factory) {
factory();
}( function() {
}(function() {
return function(fn) {
fn()().prop();
}( function() {
}(function() {
function bar() {
var quux = function() {
console.log("PASS");
@@ -1203,7 +1205,7 @@ issue_2105_1: {
return { prop: foo };
}
return bar;
} );
});
});
}
expect: {
@@ -1233,10 +1235,10 @@ issue_2105_2: {
input: {
!function(factory) {
factory();
}( function() {
}(function() {
return function(fn) {
fn()().prop();
}( function() {
}(function() {
function bar() {
var quux = function() {
console.log("PASS");
@@ -1247,7 +1249,7 @@ issue_2105_2: {
return { prop: foo };
}
return bar;
} );
});
});
}
expect: {
@@ -1256,6 +1258,44 @@ issue_2105_2: {
expect_stdout: "PASS"
}
issue_2105_3: {
options = {
inline: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
!function(factory) {
factory();
}(function() {
return function(fn) {
fn()().prop();
}(function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
});
});
}
expect: {
!void void {
prop: function() {
console.log;
void console.log("PASS");
}
}.prop();
}
expect_stdout: "PASS"
}
issue_2226_1: {
options = {
side_effects: true,
@@ -1635,7 +1675,7 @@ double_assign_2: {
}
expect: {
for (var i = 0; i < 2; i++)
void 0, a = {}, console.log(a);
a = {}, console.log(a);
var a;
}
}
@@ -1716,7 +1756,7 @@ issue_2768: {
}
expect: {
var a = "FAIL";
var c = (d = a, 0, void (d && (a = "PASS")));
var c = (d = a, void (d && (a = "PASS")));
var d;
console.log(a, typeof c);
}
@@ -2062,3 +2102,345 @@ issue_3427_2: {
}
expect_stdout: "PASS"
}
issue_3495: {
options = {
dead_code: true,
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
console.log(function f() {
f = 0;
var a = f.p;
}());
}
expect: {
console.log(void 0);
}
expect_stdout: "undefined"
}
issue_3497: {
options = {
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
var a;
console.log(function(b) {
(b += a).p = 0;
}());
}
expect: {
var a;
console.log(function(b) {
(b += a).p = 0;
}());
}
expect_stdout: "undefined"
}
issue_3515_1: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var c = 0;
(function() {
this[c++] = 0;
var expr20 = !0;
for (var key20 in expr20);
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
this[c++] = 0;
for (var key20 in !0);
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3515_2: {
options = {
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL";
function f() {
typeof b === "number";
delete a;
}
var b = f(a = "PASS");
console.log(a);
}
expect: {
var a = "FAIL";
function f() {
delete a;
}
f(a = "PASS");
console.log(a);
}
expect_stdout: "PASS"
}
issue_3515_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var c = "FAIL";
(function() {
function f() {
c = "PASS";
}
var a = f();
var a = function g(b) {
b && (b.p = this);
}(a);
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function() {
function f() {
c = "PASS";
}
(function(b) {
b && (b.p = this);
})(f());
})();
console.log(c);
}
expect_stdout: "PASS"
}
function_assign: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function() {
var a = "PASS";
function g(b) {
return b;
}
g.p = a;
function h(c) {
return c;
}
h.p = a;
return h;
}().p);
}
expect: {
console.log(function() {
var a = "PASS";
function h(c) {
return c;
}
h.p = a;
return h;
}().p);
}
expect_stdout: "PASS"
}
issue_3598: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
var a = "FAIL";
try {
(function() {
var b = void 0;
a = "PASS";
c.p = 0;
var c = b[!1];
})();
} catch (e) {}
console.log(a);
}
expect: {
var a = "FAIL";
try {
(function() {
a = "PASS";
var c = (void (c.p = 0))[!1];
})();
} catch (e) {}
console.log(a);
}
expect_stdout: "PASS"
}
self_assign: {
options = {
passes: 2,
side_effects: true,
unused: true,
}
input: {
function d(a) {
a = a;
}
function e(a, b) {
a = b;
b = a;
}
function f(a, b, c) {
a = b;
b = c;
c = a;
}
function g(a, b, c) {
a = a * b + c;
}
}
expect: {
function d(a) {}
function e(a, b) {}
function f(a, b, c) {}
function g(a, b, c) {}
}
}
function_argument_reference: {
options = {
keep_fargs: false,
side_effects: true,
unused: true,
}
input: {
var a = 1, b = 42;
function f(a) {
b <<= a;
}
f();
console.log(a, b);
}
expect: {
var a = 1, b = 42;
function f(a) {
b <<= a;
}
f();
console.log(a, b);
}
expect_stdout: "1 42"
}
function_parameter_ie8: {
options = {
ie8: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
console.log("PASS");
}
f(a = 1 + a);
})();
}
expect: {
(function() {
(function f() {
console.log("PASS");
})();
})();
}
expect_stdout: "PASS"
}
issue_3664: {
options = {
pure_getters: "strict",
unused: true,
}
input: {
console.log(function() {
var a, b = (a = (a = [ b && console.log("FAIL") ]).p = 0, 0);
return "PASS";
}());
}
expect: {
console.log(function() {
var b = ([ b && console.log("FAIL") ].p = 0, 0);
return "PASS";
}());
}
expect_stdout: "PASS"
}
issue_3673: {
options = {
pure_getters: "strict",
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
(a = [ a ]).p = 42;
console.log("PASS");
}
expect: {
var a;
(a = [ a ]).p = 42;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_3746: {
options = {
keep_fargs: "strict",
side_effects: true,
unused: true,
}
input: {
try {
A;
} catch (e) {
var e;
}
(function f(a) {
e = a;
})();
console.log("PASS");
}
expect: {
try {
A;
} catch (e) {
var e;
}
(function(a) {
e = a;
})();
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -237,22 +237,39 @@ unsafe_constant: {
unsafe: true,
}
input: {
console.log(
true.a,
false.a,
null.a,
undefined.a
);
console.log(true.a, false.a);
console.log(true.valueOf(), false.valueOf());
try {
console.log(null.a);
} catch (e) {
console.log("PASS");
}
try {
console.log(undefined.a);
} catch (e) {
console.log("PASS");
}
}
expect: {
console.log(
void 0,
false.a,
null.a,
(void 0).a
);
console.log(void 0, void 0);
console.log(true, false);
try {
console.log(null.a);
} catch (e) {
console.log("PASS");
}
try {
console.log((void 0).a);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: true
expect_stdout: [
"undefined undefined",
"true false",
"PASS",
"PASS",
]
}
unsafe_object: {
@@ -1757,3 +1774,419 @@ issue_3387_2: {
}
expect_stdout: "NaN"
}
simple_function_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function sum(a, b) {
return a + b;
}
console.log(sum(1, 2) * sum(3, 4));
}
expect: {
console.log(21);
}
expect_stdout: "21"
}
simple_function_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var sum = function(a, b) {
return a + b;
}
console.log(sum(1, 2) * sum(3, 4));
}
expect: {
console.log(21);
}
expect_stdout: "21"
}
recursive_function_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function factorial(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect: {
console.log(function factorial(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}(5));
}
expect_stdout: "120"
}
recursive_function_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var factorial = function(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect: {
var factorial = function(a) {
return a > 0 ? a * factorial(a - 1) : 1;
}
console.log(factorial(5));
}
expect_stdout: "120"
}
issue_3558: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f(a) {
return 1 + --a;
}
console.log(f(true), f(false));
}
expect: {
function f(a) {
return 1 + --a;
}
console.log(1, 0);
}
expect_stdout: "1 0"
}
issue_3568: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var a = 0;
function f(b) {
return b && b.p;
}
console.log(f(++a + f()));
}
expect: {
var a = 0;
function f(b) {
return b && b.p;
}
console.log(NaN);
}
expect_stdout: "NaN"
}
conditional_function: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f(a) {
return a && "undefined" != typeof A ? A : 42;
}
console.log(f(0), f(1));
}
expect: {
function f(a) {
return a && "undefined" != typeof A ? A : 42;
}
console.log(42, f(1));
}
expect_stdout: "42 42"
}
best_of_evaluate: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function d(x, y) {
return x / y;
}
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
}
expect: {
function d(x, y) {
return x / y;
}
console.log(0, 1 / 64, 4 / 7, 1);
console.log(0, .015625, d(4, 7), 1);
}
expect_stdout: [
"0 0.015625 0.5714285714285714 1",
"0 0.015625 0.5714285714285714 1",
]
}
eager_evaluate: {
options = {
evaluate: "eager",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function d(x, y) {
return x / y;
}
console.log(0 / 3, 1 / 64, 4 / 7, 7 / 7);
console.log(d(0, 3), d(1, 64), d(4, 7), d(7, 7));
}
expect: {
console.log(0, .015625, .5714285714285714, 1);
console.log(0, .015625, .5714285714285714, 1);
}
expect_stdout: [
"0 0.015625 0.5714285714285714 1",
"0 0.015625 0.5714285714285714 1",
]
}
threshold_evaluate_default: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b(b(b("ABCDEFGHIJK"))));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_30: {
options = {
evaluate: 30,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b(b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK")));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_100: {
options = {
evaluate: 100,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
function b(x) {
return x + x + x;
}
console.log("111", 6, b("ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"));
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
threshold_evaluate_999: {
options = {
evaluate: 999,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function b(x) {
return x + x + x;
}
console.log(b("1"), b(2), b(b(b("ABCDEFGHIJK"))));
}
expect: {
console.log("111", 6, "ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK");
}
expect_stdout: "111 6 ABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJKABCDEFGHIJK"
}
collapse_vars_regexp: {
options = {
booleans: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: true,
loops: false,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_regexp: true,
unused: true,
}
input: {
function f1() {
var k = 9;
var rx = /[A-Z]+/;
return [rx, k];
}
function f2() {
var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
function f3() {
var rx = /ab*/g;
return function() {
return rx;
};
}
(function() {
var result;
var s = "acdabcdeabbb";
var rx = /ab*/g;
while (result = rx.exec(s))
console.log(result[0]);
})();
(function() {
var result;
var s = "acdabcdeabbb";
var rx = f2();
while (result = rx(s))
console.log(result[0]);
})();
(function() {
var result;
var s = "acdabcdeabbb";
var rx = f3();
while (result = rx().exec(s))
console.log(result[0]);
})();
}
expect: {
function f1() {
return [/[A-Z]+/, 9];
}
function f2() {
var rx = /ab*/g;
return function(s) {
return rx.exec(s);
};
}
function f3() {
var rx = /ab*/g;
return function() {
return rx;
};
}
(function() {
var result, rx = /ab*/g;
while (result = rx.exec("acdabcdeabbb"))
console.log(result[0]);
})();
(function() {
var result, rx = f2();
while (result = rx("acdabcdeabbb"))
console.log(result[0]);
})();
(function() {
var result, rx = f3();
while (result = rx().exec("acdabcdeabbb"))
console.log(result[0]);
})();
}
expect_stdout: [
"a",
"ab",
"abbb",
"a",
"ab",
"abbb",
"a",
"ab",
"abbb",
]
}
issue_3738: {
options = {
evaluate: true,
}
input: {
console.log(1 / (0 + ([] - 1) % 1));
}
expect: {
console.log(1 / (0 + ([] - 1) % 1));
}
expect_stdout: "Infinity"
}
issue_3755: {
options = {
booleans: true,
evaluate: true,
unsafe: true,
unsafe_math: true,
}
input: {
console.log((/4/.exec(1 + (!0 - 5 / "23")) || 0).p);
}
expect: {
console.log((/4/.exec(!0 - 5 / "23" + 1), 0).p);
}
expect_stdout: "undefined"
}

File diff suppressed because it is too large Load Diff

View File

@@ -664,7 +664,7 @@ issue_2519: {
}
expect: {
function testFunc() {
return 1 * ((6 + 5) / 2);
return +((6 + 5) / 2);
}
console.log(testFunc());
}

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

File diff suppressed because it is too large Load Diff

View File

@@ -544,3 +544,32 @@ if_body_return_3: {
"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

@@ -30,7 +30,7 @@ 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 }
}
@@ -181,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 }
}

View File

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

View File

@@ -46,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"]

View File

@@ -1,98 +1,111 @@
issue_269_1: {
options = {
options = {
unsafe: true,
}
input: {
f(
String(x),
Number(x),
Boolean(x),
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 = {
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));
}
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 = {
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));
}
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 = {
options = {
strings: true,
unsafe: true,
}
input: {
f(
String(x + 'str'),
String('str' + x)
);
}
expect: {
f(
x + 'str',
'str' + x
);
}
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 = {
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,2]',
]
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

@@ -26,7 +26,7 @@ warn: {
}().length);
}
expect_warnings: [
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
"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]",
]
}

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

@@ -16,7 +16,6 @@ wrongly_optimized: {
function func() {
foo();
}
// TODO: optimize to `func(), bar()`
(func(), 1) && bar();
func(), 1, bar();
}
}

View File

@@ -21,7 +21,7 @@ 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();
}
}
@@ -84,6 +84,7 @@ wrongly_optimized: {
options = {
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(), 1) bar();
func(), 1;
bar();
}
}

View File

@@ -8,7 +8,7 @@ remove_sequence: {
(0, 1, _decorators.logThis)();
}
expect: {
eval();
(0, eval)();
logThis();
(0, _decorators.logThis)();
}

View File

@@ -53,20 +53,23 @@ this_binding_conditionals: {
this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
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: {
"use strict";
a();
(0, a.b)();
(0, eval)();
function f() {
"use strict";
a();
(0, a.b)();
(0, eval)();
}
}
}
@@ -97,7 +100,7 @@ this_binding_side_effects: {
(function(foo) {
foo();
(0, foo.bar)();
eval("console.log(foo);");
(0, eval)("console.log(foo);");
}());
(function(foo) {
"use strict";
@@ -144,7 +147,7 @@ this_binding_sequences: {
return eval("this");
}()),
console.log(typeof function() {
return eval("this");
return (0, eval)("this");
}()),
console.log(typeof function() {
"use strict";

View File

@@ -728,7 +728,7 @@ issue_2630_3: {
(function() {
(function f1() {
f2();
--x >= 0 && f1({});
--x >= 0 && f1();
})(a++);
function f2() {
a++;
@@ -873,13 +873,13 @@ iife_func_side_effects: {
function z() {
console.log("z");
}
(function(a, b) {
(function(b) {
return function() {
console.log("FAIL");
} + b();
})(x(), function() {
})((x(), function() {
return y();
}, z());
}), z());
}
expect_stdout: [
"x",
@@ -1155,3 +1155,303 @@ issue_3423_2: {
}
expect_stdout: "1"
}
collapse_vars_repeated: {
options = {
booleans: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
dead_code: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: "strict",
loops: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f1() {
var dummy = 3, a = 5, unused = 2, a = 1, a = 3;
return -a;
}
function f2(x) {
var a = 3, a = x;
return a;
}
(function(x) {
var a = "GOOD" + x, e = "BAD", k = "!", e = a;
console.log(e + k);
})("!"),
(function(x) {
var a = "GOOD" + x, e = "BAD" + x, k = "!", e = a;
console.log(e + k);
})("!");
}
expect: {
function f1() {
return -3;
}
function f2(x) {
return x;
}
(function() {
console.log("GOOD!!");
})(),
(function() {
console.log("GOOD!!");
})();
}
expect_stdout: true
}
chained_3: {
options = {
collapse_vars: true,
keep_fargs: "strict",
unused: true,
}
input: {
console.log(function(a, b) {
var c = a, c = b;
b++;
return c;
}(1, 2));
}
expect: {
console.log(function(b) {
var c = 1;
c = b;
b++;
return c;
}(2));
}
expect_stdout: "2"
}
replace_all_var_scope: {
rename = true
options = {
collapse_vars: true,
keep_fargs: "strict",
unused: true,
}
mangle = {}
input: {
var a = 100, b = 10;
(function(r, a) {
switch (~a) {
case (b += a):
case a++:
}
})(--b, a);
console.log(a, b);
}
expect: {
var a = 100, b = 10;
(function(c) {
switch (~a) {
case (b += a):
case c++:
}
})((--b, a));
console.log(a, b);
}
expect_stdout: "100 109"
}
issue_1583: {
options = {
keep_fargs: "strict",
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
}
}
expect: {
function m(t) {
(function() {
(function() {
return (function() {
return function(a) {};
})();
})();
})();
}
}
}
issues_3267_1: {
options = {
collapse_vars: true,
conditionals: true,
dead_code: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(x) {
x();
})(function() {
(function(i) {
if (i)
return console.log("PASS");
throw "FAIL";
})(Object());
});
}
expect: {
!function() {
if (Object())
return console.log("PASS");
throw "FAIL";
}();
}
expect_stdout: "PASS"
}
trailing_argument_side_effects: {
options = {
keep_fargs: "strict",
unused: true,
}
input: {
function f() {
return "FAIL";
}
console.log(function(a, b) {
return b || "PASS";
}(f()));
}
expect: {
function f() {
return "FAIL";
}
console.log(function(b) {
return b || "PASS";
}(void f()));
}
expect_stdout: "PASS"
}
recursive_iife_1: {
options = {
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
console.log(function f(a, b) {
return b || f("FAIL", "PASS");
}());
}
expect: {
console.log(function f(a, b) {
return b || f(0, "PASS");
}());
}
expect_stdout: "PASS"
}
recursive_iife_2: {
options = {
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
console.log(function f(a, b) {
return b || f("FAIL", "PASS");
}(null, 0));
}
expect: {
console.log(function f(a, b) {
return b || f(0, "PASS");
}(0, 0));
}
expect_stdout: "PASS"
}
recursive_iife_3: {
options = {
keep_fargs: false,
reduce_vars: true,
unused: true,
}
input: {
var a = 1, c = "PASS";
(function() {
function f(b, d, e) {
a-- && f(null, 42, 0);
e && (c = "FAIL");
d && d.p;
}
var a_1 = f();
})();
console.log(c);
}
expect: {
var a = 1, c = "PASS";
(function() {
(function f(b, d, e) {
a-- && f(0, 42, 0);
e && (c = "FAIL");
d && d.p;
})();
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3619: {
options = {
keep_fargs: false,
unused: true,
}
input: {
var a = 1, b = "FAIL";
(function f(c, d) {
function g() {
d && (b = "PASS", 0 <= --a && g());
0 <= --a && f(0, "function");
}
g();
})();
console.log(b);
}
expect: {
var a = 1, b = "FAIL";
(function f(c, d) {
function g() {
d && (b = "PASS", 0 <= --a && g());
0 <= --a && f(0, "function");
}
g();
})();
console.log(b);
}
expect_stdout: "PASS"
}

View File

@@ -6,7 +6,7 @@ while_becomes_for: {
while (foo()) bar();
}
expect: {
for (; foo(); ) bar();
for (;foo();) bar();
}
}
@@ -19,7 +19,7 @@ drop_if_break_1: {
if (foo()) break;
}
expect: {
for (; !foo(););
for (;!foo(););
}
}
@@ -32,7 +32,7 @@ drop_if_break_2: {
if (foo()) break;
}
expect: {
for (; bar() && !foo(););
for (;bar() && !foo(););
}
}
@@ -70,7 +70,7 @@ drop_if_break_4: {
}
}
expect: {
for (; bar() && (x(), y(), !foo());) z(), k();
for (;bar() && (x(), y(), !foo());) z(), k();
}
}
@@ -82,7 +82,7 @@ drop_if_else_break_1: {
for (;;) if (foo()) bar(); else break;
}
expect: {
for (; foo(); ) bar();
for (;foo();) bar();
}
}
@@ -97,7 +97,7 @@ drop_if_else_break_2: {
}
}
expect: {
for (; bar() && foo();) baz();
for (;bar() && foo();) baz();
}
}
@@ -114,7 +114,7 @@ drop_if_else_break_3: {
}
}
expect: {
for (; bar() && foo();) {
for (;bar() && foo();) {
baz();
stuff1();
stuff2();
@@ -138,7 +138,7 @@ drop_if_else_break_4: {
}
}
expect: {
for (; bar() && (x(), y(), foo());) baz(), z(), k();
for (;bar() && (x(), y(), foo());) baz(), z(), k();
}
}
@@ -523,13 +523,13 @@ issue_2740_1: {
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 (;;) 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: {
@@ -574,9 +574,11 @@ issue_2740_3: {
console.log(x, y);
}
expect: {
L1: for (var x = 0; x < 3; x++)
for (var y = 0; y < 2; y++)
L1: for (var x = 0; x < 3; x++) {
var y = 0;
if (y < 2)
break L1;
}
console.log(x, y);
}
expect_stdout: "0 0"
@@ -668,7 +670,7 @@ issue_3371: {
function a() {
console.log("PASS");
}
for (; a(); );
for (;a(););
})();
}
expect_stdout: "PASS"
@@ -689,3 +691,239 @@ step: {
}
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"
}

File diff suppressed because it is too large Load Diff

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

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

View File

@@ -817,6 +817,29 @@ issue_2208_5: {
expect_stdout: "42"
}
issue_2208_6: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
a = 42;
console.log(("FAIL", {
p: function() {
return this.a;
}
}.p)());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
}
issue_2256: {
options = {
side_effects: true,

View File

@@ -1193,6 +1193,7 @@ issue_3427: {
assignments: true,
collapse_vars: true,
inline: true,
passes: 2,
pure_getters: "strict",
sequences: true,
side_effects: true,
@@ -1206,4 +1207,5 @@ issue_3427: {
})(a || (a = {}));
}
expect: {}
expect_stdout: true
}

View File

@@ -1427,13 +1427,13 @@ defun_inline_3: {
defun_call: {
options = {
inline: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
console.log(function f() {
return g() + h(1) - h(g(), 2, 3);
function g() {
return 4;
@@ -1441,21 +1441,17 @@ defun_call: {
function h(a) {
return a;
}
}
}());
}
expect: {
function f() {
return 4 + h(1) - h(4);
function h(a) {
return a;
}
}
console.log(1);
}
expect_stdout: "1"
}
defun_redefine: {
options = {
inline: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -1480,7 +1476,7 @@ defun_redefine: {
(function() {
return 3;
});
return 3 + 2;
return 5;
}
console.log(f());
}
@@ -1517,7 +1513,7 @@ func_inline: {
func_modified: {
options = {
inline: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -1550,7 +1546,7 @@ func_modified: {
(function() {
return 4;
});
return 1 + 2 + 4;
return 7;
}
console.log(f());
}
@@ -2075,13 +2071,8 @@ issue_1670_6: {
}
expect: {
(function(a) {
switch (1) {
case a = 1:
console.log(a);
break;
default:
console.log(2);
}
a = 1;
console.log(a);
})(1);
}
expect_stdout: "1"
@@ -2298,11 +2289,10 @@ redefine_farg_2: {
console.log(f([]), g([]), h([]));
}
expect: {
console.log((a = [], typeof a), "number",function(a, b) {
console.log(typeof [], "number",function(a, b) {
a = b;
return typeof a;
}([]));
var a;
}
expect_stdout: "object number undefined"
}
@@ -4947,7 +4937,7 @@ defun_single_use_loop: {
unused: true,
}
input: {
for (var x, i = 2; --i >= 0; ) {
for (var x, i = 2; --i >= 0;) {
var y = x;
x = f;
console.log(x === y);
@@ -4955,7 +4945,7 @@ defun_single_use_loop: {
function f() {};
}
expect: {
for (var x, i = 2; --i >= 0; ) {
for (var x, i = 2; --i >= 0;) {
var y = x;
x = f;
console.log(x === y);
@@ -5516,9 +5506,7 @@ issue_2860_1: {
}());
}
expect: {
console.log(function(a) {
return 1 ^ a;
}());
console.log(1);
}
expect_stdout: "1"
}
@@ -6522,17 +6510,17 @@ issue_3240_3: {
}
expect: {
(function() {
(function f(b) {
f();
function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
var g = function() {
(function() {
(b ? function() {} : function() {
f.a++;
f(1);
})();
};
g();
})();
})();
}
})();
}
expect_stdout: [
@@ -6566,7 +6554,8 @@ issue_3240_4: {
}
expect: {
(function() {
(function f(b) {
f();
function f(b) {
if (!f.a) f.a = 0;
console.log(f.a.toString());
(function() {
@@ -6575,7 +6564,7 @@ issue_3240_4: {
f(1);
})();
})();
})();
}
})();
}
expect_stdout: [
@@ -6609,10 +6598,10 @@ issues_3267_1: {
}
expect: {
!function(i) {
if (i)
if (Object())
return console.log("PASS");
throw "FAIL";
}(Object());
}();
}
expect_stdout: "PASS"
}
@@ -6752,3 +6741,174 @@ issue_3377: {
}
expect_stdout: "42"
}
issue_3509: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function a() {
console.log("PASS");
}
try {
} catch (a) {
var a;
}
a();
}
expect: {
try {
} catch (a) {
var a;
}
(function() {
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_3622: {
options = {
evaluate: true,
inline: true,
keep_fargs: "strict",
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var c = "FAIL";
!function(b, a) {
a && (c = "PASS");
}(42, this);
console.log(c);
}
expect: {
var c = "FAIL";
var a;
a = this,
!void (a && (c = "PASS")),
console.log(c);
}
expect_stdout: "PASS"
}
issue_3631_1: {
options = {
evaluate: 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;
L: do {
for (;;) continue L;
var b = 1;
} while (b && c++);
console.log(c);
}
expect_stdout: "0"
}
issue_3631_2: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
L: for (var a = 1; a--; console.log(b)) {
for (;;) continue L;
var b = "FAIL";
}
}
expect: {
L: for (var a = 1; a--; console.log(b)) {
for (;;) continue L;
var b = "FAIL";
}
}
expect_stdout: "undefined"
}
issue_3666: {
options = {
collapse_vars: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
try {
var a = "FAIL";
} finally {
for (;!a;)
var c = a++;
var a = "PASS", b = c = "PASS";
}
console.log(a, b);
}
expect: {
try {
var a = "FAIL";
} finally {
for (;!a;)
a++;
var b = a = "PASS";
}
console.log(a, b);
}
expect_stdout: "PASS PASS"
}
issue_3774: {
options = {
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
var f = function() {
function g() {
if (!g.p) {
g.p = 1;
console.log("PASS");
}
}
return function() {
g();
};
}();
f();
f();
}
expect: {
var f = function() {
function g() {
if (!g.p) {
g.p = 1;
console.log("PASS");
}
}
return function() {
g();
};
}();
f();
f();
}
expect_stdout: "PASS"
}

View File

@@ -36,6 +36,20 @@ regexp_2: {
expect_stdout: '["PASS","pass"]'
}
regexp_properties: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(/abc/g.source, /abc/g.global, /abc/g.ignoreCase, /abc/g.lastIndex, /abc/g.multiline);
}
expect: {
console.log("abc", true, false, /abc/g.lastIndex, false);
}
expect_stdout: "abc true false 0 false"
}
issue_3434_1: {
options = {
evaluate: true,
@@ -172,3 +186,290 @@ issue_3434_3: {
/\nfo\n[\n]o\bbb/;
}
}
issue_3434_4: {
options = {
evaluate: true,
unsafe: true,
}
input: {
[
[ "", RegExp("") ],
[ "/", RegExp("/") ],
[ "//", RegExp("//") ],
[ "\/", RegExp("\\/") ],
[ "///", RegExp("///") ],
[ "/\/", RegExp("/\\/") ],
[ "\//", RegExp("\\//") ],
[ "\\/", RegExp("\\\\/") ],
[ "////", RegExp("////") ],
[ "//\/", RegExp("//\\/") ],
[ "/\//", RegExp("/\\//") ],
[ "/\\/", RegExp("/\\\\/") ],
[ "\///", RegExp("\\///") ],
[ "\/\/", RegExp("\\/\\/") ],
[ "\\//", RegExp("\\\\//") ],
[ "\\\/", RegExp("\\\\\\/") ],
].forEach(function(test) {
console.log(test[1].test("\\"), test[1].test(test[0]));
});
}
expect: {
[
[ "", /(?:)/ ],
[ "/", /\// ],
[ "//", /\/\// ],
[ "/", /\// ],
[ "///", /\/\/\// ],
[ "//", /\/\// ],
[ "//", /\/\// ],
[ "\\/", /\\\// ],
[ "////", /\/\/\/\// ],
[ "///", /\/\/\// ],
[ "///", /\/\/\// ],
[ "/\\/", /\/\\\// ],
[ "///", /\/\/\// ],
[ "//", /\/\// ],
[ "\\//", /\\\/\// ],
[ "\\/", /\\\// ],
].forEach(function(test) {
console.log(test[1].test("\\"), test[1].test(test[0]));
});
}
expect_stdout: [
"true true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
"false true",
]
}
exec: {
options = {
evaluate: true,
loops: true,
unsafe: true,
}
input: {
while (/a/.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
exec_global: {
options = {
evaluate: true,
loops: true,
unsafe: true,
}
input: {
while (/a/g.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
test: {
options = {
evaluate: true,
unsafe: true,
}
input: {
while (/a/.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
test_global: {
options = {
evaluate: true,
unsafe: true,
}
input: {
while (/a/g.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_exec: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/;
while (r.exec("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
var r = /a/;
for (;null;)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_exec_global: {
options = {
evaluate: true,
loops: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/g;
while (r.exec("aaa"))
console.log("PASS");
}
expect: {
var r = /a/g;
for (;r.exec("aaa");)
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
}
var_test: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/;
while (r.test("AAA"))
console.log("FAIL");
console.log("PASS");
}
expect: {
var r = /a/;
while (false)
console.log("FAIL");
console.log("PASS");
}
expect_stdout: "PASS"
}
var_test_global: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var r = /a/g;
while (r.test("aaa"))
console.log("PASS");
}
expect: {
var r = /a/g;
while (r.test("aaa"))
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
]
}
lazy_boolean: {
options = {
evaluate: true,
passes: 2,
side_effects: true,
unsafe: true,
}
input: {
/b/.exec({}) && console.log("PASS");
/b/.test({}) && console.log("PASS");
/b/g.exec({}) && console.log("PASS");
/b/g.test({}) && console.log("PASS");
}
expect: {
console.log("PASS");
console.log("PASS");
console.log("PASS");
console.log("PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
]
}
reset_state_between_evaluate: {
options = {
evaluate: true,
passes: 2,
unsafe: true,
}
input: {
console.log(function() {
for (var a in /[abc4]/g.exec("a"))
return "PASS";
return "FAIL";
}());
}
expect: {
console.log(function() {
for (var a in /[abc4]/g.exec("a"))
return "PASS";
return "FAIL";
}());
}
expect_stdout: "PASS"
}

View File

@@ -579,7 +579,7 @@ function_do_catch_ie8: {
console.log(b, c);
}
expect: {
var t = 1, u = 1, y = 0;
var u = 1, y = 1, a = 0;
function c(c) {
var d;
do {
@@ -587,7 +587,7 @@ function_do_catch_ie8: {
try {
var e = void 0;
} catch (i) {
--t && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
--u && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
0;
0;
0;
@@ -596,18 +596,146 @@ function_do_catch_ie8: {
d[1];
} catch (l) {
var g;
switch(function x() {
y++;
switch (function n() {
a++;
}()) {
case e + --g:
case e + --g:
}
}
} catch (n) {}
} catch (t) {}
} while (--d);
u--;
y--;
}
c();
console.log(u, y);
console.log(y, a);
}
expect_stdout: "0 1"
}
issue_3480: {
rename = true,
mangle = {
ie8: false,
toplevel: false,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var d, a, b, c = "FAIL";
(function n() {
(function() {
try {
c = "PASS";
} catch (c) {}
})();
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3480_ie8: {
rename = true,
mangle = {
ie8: true,
toplevel: false,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {}
})();
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3480_toplevel: {
rename = true,
mangle = {
ie8: false,
toplevel: true,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var c, n, o, t = "FAIL";
(function c() {
(function() {
try {
t = "PASS";
} catch (c) {}
})();
})();
console.log(t);
}
expect_stdout: "PASS"
}
issue_3480_ie8_toplevel: {
rename = true,
mangle = {
ie8: true,
toplevel: true,
}
input: {
var d, a, b, c = "FAIL";
(function b() {
(function() {
try {
c = "PASS";
} catch (b) {
}
})();
})();
console.log(c);
}
expect: {
var c, n, o, t = "FAIL";
(function o() {
(function() {
try {
t = "PASS";
} catch (o) {}
})();
})();
console.log(t);
}
expect_stdout: "PASS"
}

View File

@@ -910,15 +910,23 @@ call: {
console.log(this === b ? "bar" : "baz");
};
(a, b)();
(a, b).c();
(a, b.c)();
(a, b)["c"]();
(a, b["c"])();
(a, function() {
console.log(this === a);
})();
new (a, b)();
new (a, b).c();
new (a, b.c)();
new (a, b)["c"]();
new (a, b["c"])();
new (a, function() {
console.log(this === a);
})();
console.log(typeof (a, b).c);
console.log(typeof (a, b)["c"]);
}
expect: {
var a = function() {
@@ -931,23 +939,39 @@ call: {
console.log(this === b ? "bar" : "baz");
},
b(),
b.c(),
(a, b.c)(),
b["c"](),
(a, b["c"])(),
function() {
console.log(this === a);
}(),
new b(),
new b.c(),
new b.c(),
new b["c"](),
new b["c"](),
new function() {
console.log(this === a);
}();
}(),
console.log((a, typeof b.c)),
console.log((a, typeof b["c"]));
}
expect_stdout: [
"foo",
"bar",
"baz",
"bar",
"baz",
"true",
"foo",
"baz",
"baz",
"baz",
"baz",
"false",
"function",
"function",
]
}
@@ -1006,3 +1030,85 @@ angularjs_chain: {
}
}
}
issue_3490_1: {
options = {
conditionals: true,
dead_code: true,
inline: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var b = 42, c = "FAIL";
if ({
3: function() {
var a;
return (a && a.p) < this;
}(),
}) c = "PASS";
if (b) while ("" == typeof d);
console.log(c, b);
}
expect: {
var b = 42, c = "FAIL";
if (function() {
var a;
a && a.p;
}(), c = "PASS", b) while ("" == typeof d);
console.log(c, b);
}
expect_stdout: "PASS 42"
}
issue_3490_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
inline: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var b = 42, c = "FAIL";
if ({
3: function() {
var a;
return (a && a.p) < this;
}(),
}) c = "PASS";
if (b) for (; "" == typeof d;);
console.log(c, b);
}
expect: {
var b = 42, c = "FAIL";
for (function() {
var a;
}(), c = "PASS", b; "" == typeof d;);
console.log(c, b);
}
expect_stdout: "PASS 42"
}
issue_3703: {
options = {
evaluate: true,
sequences: true,
unsafe: true,
}
input: {
var a = "FAIL";
while ((a = "PASS", 0).foo = 0);
console.log(a);
}
expect: {
var a = "FAIL";
while (a = "PASS", (0).foo = 0);
console.log(a);
}
expect_stdout: "PASS"
}

View File

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

View File

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

View File

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

View File

@@ -166,9 +166,7 @@ duplicate_lambda_arg_name: {
}());
}
expect: {
console.log(function long_name(long_name) {
return typeof long_name;
}());
console.log("undefined");
}
expect_stdout: "undefined"
}
@@ -295,3 +293,145 @@ issue_2728_6: {
}
expect_stdout: "function undefined"
}
typeof_defined_1: {
options = {
side_effects: true,
typeofs: true,
}
input: {
"undefined" == typeof A && A;
"undefined" != typeof A && A;
"undefined" == typeof A || A;
"undefined" != typeof A || A;
}
expect: {
"undefined" == typeof A && A;
"undefined" != typeof A || A;
}
}
typeof_defined_2: {
options = {
side_effects: true,
typeofs: true,
}
input: {
"function" == typeof A && A;
"function" != typeof A && A;
"function" == typeof A || A;
"function" != typeof A || A;
}
expect: {
"function" != typeof A && A;
"function" == typeof A || A;
}
}
typeof_defined_3: {
options = {
side_effects: true,
typeofs: true,
}
input: {
"undefined" == typeof A && "undefined" == typeof B && (A, B);
"undefined" == typeof A && "undefined" != typeof B && (A, B);
"undefined" != typeof A && "undefined" == typeof B && (A, B);
"undefined" != typeof A && "undefined" != typeof B && (A, B);
"undefined" == typeof A && "undefined" == typeof B || (A, B);
"undefined" == typeof A && "undefined" != typeof B || (A, B);
"undefined" != typeof A && "undefined" == typeof B || (A, B);
"undefined" != typeof A && "undefined" != typeof B || (A, B);
"undefined" == typeof A || "undefined" == typeof B && (A, B);
"undefined" == typeof A || "undefined" != typeof B && (A, B);
"undefined" != typeof A || "undefined" == typeof B && (A, B);
"undefined" != typeof A || "undefined" != typeof B && (A, B);
"undefined" == typeof A || "undefined" == typeof B || (A, B);
"undefined" == typeof A || "undefined" != typeof B || (A, B);
"undefined" != typeof A || "undefined" == typeof B || (A, B);
"undefined" != typeof A || "undefined" != typeof B || (A, B);
}
expect: {
"undefined" == typeof A && "undefined" == typeof B && (A, B);
"undefined" == typeof A && "undefined" != typeof B && A;
"undefined" != typeof A && "undefined" == typeof B && B;
"undefined" == typeof A && "undefined" == typeof B || (A, B);
"undefined" == typeof A && "undefined" != typeof B || (A, B);
"undefined" != typeof A && "undefined" == typeof B || (A, B);
"undefined" != typeof A && "undefined" != typeof B || (A, B);
"undefined" == typeof A || "undefined" == typeof B && B;
"undefined" != typeof A || "undefined" == typeof B && (A, B);
"undefined" != typeof A || "undefined" != typeof B && A;
"undefined" == typeof A || "undefined" != typeof B || B;
"undefined" != typeof A || "undefined" == typeof B || A;
"undefined" != typeof A || "undefined" != typeof B || (A, B);
}
}
typeof_defined_4: {
options = {
side_effects: true,
typeofs: true,
}
input: {
"object" == typeof A && "object" == typeof B && (A, B);
"object" == typeof A && "object" != typeof B && (A, B);
"object" != typeof A && "object" == typeof B && (A, B);
"object" != typeof A && "object" != typeof B && (A, B);
"object" == typeof A && "object" == typeof B || (A, B);
"object" == typeof A && "object" != typeof B || (A, B);
"object" != typeof A && "object" == typeof B || (A, B);
"object" != typeof A && "object" != typeof B || (A, B);
"object" == typeof A || "object" == typeof B && (A, B);
"object" == typeof A || "object" != typeof B && (A, B);
"object" != typeof A || "object" == typeof B && (A, B);
"object" != typeof A || "object" != typeof B && (A, B);
"object" == typeof A || "object" == typeof B || (A, B);
"object" == typeof A || "object" != typeof B || (A, B);
"object" != typeof A || "object" == typeof B || (A, B);
"object" != typeof A || "object" != typeof B || (A, B);
}
expect: {
"object" == typeof A && "object" != typeof B && B;
"object" != typeof A && "object" == typeof B && A;
"object" != typeof A && "object" != typeof B && (A, B);
"object" == typeof A && "object" == typeof B || (A, B);
"object" == typeof A && "object" != typeof B || (A, B);
"object" != typeof A && "object" == typeof B || (A, B);
"object" != typeof A && "object" != typeof B || (A, B);
"object" == typeof A || "object" == typeof B && A;
"object" == typeof A || "object" != typeof B && (A, B);
"object" != typeof A || "object" != typeof B && B;
"object" == typeof A || "object" == typeof B || (A, B);
"object" == typeof A || "object" != typeof B || A;
"object" != typeof A || "object" == typeof B || B;
}
}
emberjs_global: {
options = {
comparisons: true,
conditionals: true,
if_return: true,
passes: 2,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
var a;
if (typeof A === "object") {
a = A;
} else if (typeof B === "object") {
a = B;
} else {
throw new Error("PASS");
}
}
expect: {
if ("object" != typeof A && "object" != typeof B)
throw new Error("PASS");
}
expect_stdout: Error("PASS")
}

View File

@@ -16,6 +16,81 @@ unicode_parse_variables: {
}
}
unicode_escaped_identifier: {
input: {
var \u0061 = "\ud800\udc00";
console.log(a);
}
expect_exact: 'var a="\ud800\udc00";console.log(a);'
expect_stdout: "\ud800\udc00"
}
unicode_identifier_ascii_only: {
beautify = {
ascii_only: true,
}
input: {
var \u0061 = "testing \udbc4\udd11";
var bar = "h\u0065llo";
console.log(a, \u0062\u0061r);
}
expect_exact: 'var a="testing \\udbc4\\udd11";var bar="hello";console.log(a,bar);'
expect_stdout: "testing \udbc4\udd11 hello"
}
unicode_string_literals: {
beautify = {
ascii_only: true,
}
input: {
var a = "6 length unicode character: \udbc4\udd11";
console.log(\u0061);
}
expect_exact: 'var a="6 length unicode character: \\udbc4\\udd11";console.log(a);'
expect_stdout: "6 length unicode character: \udbc4\udd11"
}
check_escape_style: {
beautify = {
ascii_only: true,
}
input: {
var a = "\x01";
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
var \u0100 = "\u0100";
var \u1000 = "\u1000";
var \u1000 = "\ud800\udc00";
var \u3f80 = "\udbc0\udc00";
console.log(\u0061, \ua0081, \u0100, \u1000, \u3f80);
}
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u1000="\\ud800\\udc00";var \\u3f80="\\udbc0\\udc00";console.log(a,\\ua0081,\\u0100,\\u1000,\\u3f80);'
expect_stdout: "\u0001 \u0010 \u0100 \ud800\udc00 \udbc0\udc00"
}
escape_non_escaped_identifier: {
beautify = {
ascii_only: true,
}
input: {
var µþ = "µþ";
console.log(\u00b5þ);
}
expect_exact: 'var \\u00b5\\u00fe="\\xb5\\xfe";console.log(\\u00b5\\u00fe);'
expect_stdout: "µþ"
}
non_escape_2_non_escape: {
beautify = {
ascii_only: false,
}
input: {
var µþ = "µþ";
console.log(\u00b5þ);
}
expect_exact: 'var µþ="µþ";console.log(µþ);'
expect_stdout: "µþ"
}
issue_2242_1: {
beautify = {
ascii_only: false,
@@ -24,6 +99,7 @@ issue_2242_1: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
expect_stdout: "\ud83d \ude00 \ud83d\ude00 \ud83d@\ude00"
}
issue_2242_2: {
@@ -34,6 +110,7 @@ issue_2242_2: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
expect_stdout: "\ud83d \ude00 \ud83d\ude00 \ud83d@\ude00"
}
issue_2242_3: {
@@ -44,6 +121,7 @@ issue_2242_3: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
expect_stdout: "\ud83d\ude00 \ud83d@\ude00"
}
issue_2242_4: {
@@ -54,6 +132,7 @@ issue_2242_4: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
expect_stdout: "\ud83d\ude00 \ud83d@\ude00"
}
issue_2569: {

View File

@@ -1,6 +1,7 @@
exports["Compressor"] = Compressor;
exports["defaults"] = defaults;
exports["JS_Parse_Error"] = JS_Parse_Error;
exports["List"] = List;
exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify;
exports["OutputStream"] = OutputStream;
@@ -8,6 +9,8 @@ exports["parse"] = parse;
exports["push_uniq"] = push_uniq;
exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template;
exports["to_ascii"] = to_ascii;
exports["tokenizer"] = tokenizer;
exports["TreeTransformer"] = TreeTransformer;
exports["TreeWalker"] = TreeWalker;
exports["vlq_decode"] = vlq_decode;

View File

@@ -0,0 +1,17 @@
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
function f() {
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
}

View File

@@ -1,17 +1 @@
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
function f() {
if (x) foo();
if (x) foo(); else baz();
if (x) foo(); else if (y) bar(); else baz();
if (x) if (y) foo(); else bar(); else baz();
if (x) foo(); else if (y) bar(); else if (z) baz(); else moo();
}
if(x)foo();if(x)foo();else baz();if(x)foo();else if(y)bar();else baz();if(x)if(y)foo();else bar();else baz();if(x)foo();else if(y)bar();else if(z)baz();else moo();function f(){if(x)foo();if(x)foo();else baz();if(x)foo();else if(y)bar();else baz();if(x)if(y)foo();else bar();else baz();if(x)foo();else if(y)bar();else if(z)baz();else moo()}

View File

@@ -1,2 +1,2 @@
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCB7Zm9vfSA9IHJlcXVpcmUoXCJiYXJcIik7XG5jb25zdCB7aGVsbG99ID0gcmVxdWlyZShcIndvcmxkXCIpO1xuXG5mb28ueCguLi5mb28ueShoZWxsby56KSk7XG4iXSwibmFtZXMiOlsicmVxdWlyZSIsImFyciJdLCJtYXBwaW5ncyI6IjBKQUFjQSxLQUFRQyJ9

View File

@@ -1,2 +1,2 @@
new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9

View File

@@ -0,0 +1,8 @@
// Generated by CoffeeScript 2.4.1
(function() {
console.log('hello');
}).call(this);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1haW4uY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtFQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksT0FBWjtBQUFBIiwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2cgJ2hlbGxvJ1xuIl19
//# sourceURL=/Users/mohamed/Downloads/main.coffee

View File

@@ -1,2 +1,2 @@
new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9

View File

@@ -0,0 +1,9 @@
var o = this;
for (var k in o) L17060: {
a++;
}
var a;
console.log(k);

View File

@@ -0,0 +1,15 @@
// (beautified)
var o = this;
for (var k in o) {}
var a;
console.log(k);
// output: a
//
// minify: k
//
// options: {
// "mangle": false
// }

View File

@@ -0,0 +1,8 @@
console.log(function f(a) {
({
set p(v) {
f++;
}
});
return f.length;
}());

View File

@@ -0,0 +1,20 @@
// (beautified)
console.log(function f(a) {
({
set p(v) {
f++;
}
});
return f.length;
}());
// output: 1
//
// minify: 0
//
// options: {
// "compress": {
// "keep_fargs": false,
// "unsafe": true
// },
// "mangle": false
// }

View File

@@ -0,0 +1,18 @@
var _calls_ = 10, a = 100, b = 10, c = 0;
function f0(b_1, a, undefined_2) {
a++ + ++b;
{
var expr2 = (b + 1 - .1 - .1 - .1 || a || 3).toString();
L20778: for (var key2 in expr2) {
(c = c + 1) + [ --b + b_1, typeof f0 == "function" && --_calls_ >= 0 && f0(--b + typeof (undefined_2 = 1 === 1 ? a : b), --b + {
c: (c = c + 1) + null
}, a++ + (typeof f0 == "function" && --_calls_ >= 0 && f0(typeof (c = 1 + c, 3 / "a" * ("c" >>> 23..toString()) >= (b_1 && (b_1[(c = c + 1) + a--] = (- -0,
true + {})))), 3, 25))), 1 === 1 ? a : b ];
}
}
}
var a_1 = f0([ , 0 ].length === 2);
console.log(null, a, b, c, Infinity, NaN, undefined);

View File

@@ -0,0 +1,20 @@
// (beautified)
var b = 0;
var expr2 = (0 - 1 - .1 - .1).toString();
for (var key2 in expr2) {
--b;
}
console.log(b);
// output: -19
//
// minify: -4
//
// options: {
// "compress": {
// "unsafe_math": true
// },
// "mangle": false
// }

View File

@@ -1,6 +1,6 @@
function f(x) {
return g(x);
function g(x) {
return x;
return x + x;
}
}

View File

@@ -8,15 +8,14 @@ if (typeof phantom == "undefined") {
require("../tools/exit");
var args = process.argv.slice(2);
var debug = args.indexOf("--debug");
if (debug >= 0) {
if (debug < 0) {
debug = false;
} else {
args.splice(debug, 1);
debug = true;
} else {
debug = false;
}
if (!args.length) {
args.push("-mcb", "beautify=false,webkit");
}
args.unshift("bin/uglifyjs");
if (!args.length) args.push("-mcb", "beautify=false,webkit");
args.push("--timings");
var child_process = require("child_process");
var fetch = require("./fetch");
@@ -39,7 +38,7 @@ if (typeof phantom == "undefined") {
});
if (/\.js$/.test(url)) {
var stderr = "";
var uglifyjs = child_process.fork("bin/uglifyjs", args, {
var uglifyjs = child_process.spawn(process.argv[0], args, {
silent: true
}).on("exit", function(code) {
console.log("uglifyjs", url.slice(site.length + 1), args.join(" "));

View File

@@ -1,7 +1,7 @@
var fs = require("fs");
var config = {
limit: 5000,
limit: 10000,
timeout: function(limit) {
this.limit = limit;
}
@@ -55,11 +55,11 @@ process.nextTick(function run() {
var elapsed = Date.now();
var timer;
var done = function() {
reset();
elapsed = Date.now() - elapsed;
if (elapsed > task.limit) {
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
}
reset();
log_titles(console.log, task.titles, green('\u221A '));
process.nextTick(run);
};

View File

@@ -12,7 +12,9 @@ describe("bin/uglifyjs", function() {
it("Should produce a functional build when using --self", function(done) {
this.timeout(30000);
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
exec(command, function(err, stdout) {
exec(command, {
maxBuffer: 1048576
}, function(err, stdout) {
if (err) throw err;
eval(stdout);
assert.strictEqual(typeof WrappedUglifyJS, "object");
@@ -174,7 +176,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
assert.strictEqual(stdout, read("test/input/issue-1482/beautify.js"));
done();
});
});
@@ -186,6 +188,22 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should work with `--output-opts`", function(done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -O';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
done();
});
});
it("Should fail when both --beautify & --output-opts are specified", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js -bO";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: --beautify cannot be used with --output-opts\n");
done();
});
});
it("Should process inline source map", function(done) {
var command = [
uglifyjscmd,
@@ -227,7 +245,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err;
assert.strictEqual(stdout, [
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxJQUFPLElBQUlGLElDQW5ELElBQUlHLElBQU0sV0FDTixTQUFTQyxJQUFLRCxLQUNWLE9BQU9BLElBR1gsT0FBT0MsSUFMRCJ9",
"",
].join("\n"));
var stderrLines = stderr.split("\n");
@@ -569,7 +587,7 @@ describe("bin/uglifyjs", function() {
});
function read_map() {
var map = JSON.parse(read("./test/input/issue-1236/simple.js.map"));
var map = JSON.parse(read("test/input/issue-1236/simple.js.map"));
delete map.sourcesContent;
return JSON.stringify(map).replace(/"/g, '\\"');
}
@@ -656,7 +674,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/rename/input.js --rename";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c}}\n");
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+c}}\n");
done();
});
});
@@ -664,7 +682,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
assert.strictEqual(stdout, "function f(n){return function(n){return n+n}(n)}\n");
done();
});
});
@@ -672,7 +690,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "function f(n){return n}\n");
assert.strictEqual(stdout, "function f(n){return n+n}\n");
done();
});
});
@@ -680,7 +698,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");
assert.strictEqual(stdout, "function f(x){return function(x){return x+x}(x)}\n");
done();
});
});

View File

@@ -48,53 +48,84 @@ describe("comments", function() {
}
});
it("Should handle comment within return correctly", function() {
var result = UglifyJS.minify([
"function unequal(x, y) {",
" return (",
" // Either one",
" x < y",
" ||",
" y < x",
" );",
"}",
].join("\n"), {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
describe("comment within return", function() {
it("Should handle leading return", function() {
var result = UglifyJS.minify([
"function unequal(x, y) {",
" return (",
" // Either one",
" x < y",
" ||",
" y < x",
" );",
"}",
].join("\n"), {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function unequal(x, y) {",
" // Either one",
" return x < y || y < x;",
"}",
].join("\n"));
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function unequal(x, y) {",
" // Either one",
" return x < y || y < x;",
"}",
].join("\n"));
});
it("Should handle comment folded into return correctly", function() {
var result = UglifyJS.minify([
"function f() {",
" /* boo */ x();",
" return y();",
"}",
].join("\n"), {
mangle: false,
output: {
beautify: true,
comments: "all",
},
it("Should handle trailing return", function() {
var result = UglifyJS.minify([
"function unequal(x) {",
" var y;",
" return (",
" // Either one",
" x < y",
" ||",
" y < x",
" );",
"}",
].join("\n"), {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function unequal(x) {",
" var y;",
" // Either one",
" return x < y || y < x;",
"}",
].join("\n"));
});
it("Should handle comment folded into return", function() {
var result = UglifyJS.minify([
"function f() {",
" /* boo */ x();",
" return y();",
"}",
].join("\n"), {
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function f() {",
" /* boo */",
" return x(), y();",
"}",
].join("\n"));
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function f() {",
" /* boo */",
" return x(), y();",
"}",
].join("\n"));
});
it("Should not drop comments after first OutputStream", function() {
@@ -228,6 +259,30 @@ describe("comments", function() {
assert.strictEqual(result.code, code);
});
it("Should handle comments around parenthesis correctly", function() {
var code = [
"a();",
"/* foo */",
"(b())",
"/* bar */",
"c();",
].join("\n");
var result = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"a();",
"/* foo */",
"b()",
"/* bar */;c();",
].join("\n"));
});
it("Should preserve comments around IIFE", function() {
var result = UglifyJS.minify("/*a*/(/*b*/function(){/*c*/}/*d*/)/*e*/();", {
compress: false,

View File

@@ -54,8 +54,8 @@ describe("Directives", function() {
[
[
'"use strict"\n',
[ "use strict"],
[ "use asm"]
[ "use strict" ],
[ "use asm" ]
],
[
'"use\\\nstrict";',
@@ -69,19 +69,19 @@ describe("Directives", function() {
],
[
'"use \\\nstrict";"use strict";',
[],
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
[ "use strict" ],
[ "use\nstrict", "use \nstrict", "use asm" ]
],
[
'"\\76";',
[],
[ ">", "\\76" ]
[ "\\76" ],
[ ">" ]
],
[
// no ; or newline
'"use strict"',
[],
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
[ "use strict" ],
[ "use\nstrict", "use \nstrict", "use asm" ]
],
[
';"use strict"',
@@ -106,18 +106,18 @@ describe("Directives", function() {
],
[
'function foo() {"use \\\nstrict";"use strict";',
[],
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
[ "use strict" ],
[ "use\nstrict", "use \nstrict", "use asm" ]
],
[
'var foo = function() {"\\76";',
[],
[ ">", "\\76" ]
[ "\\76" ],
[ ">" ]
],
[
'var foo = function() {"use strict"', // no ; or newline
[],
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
[ "use strict" ],
[ "use\nstrict", "use \nstrict", "use asm" ]
],
[
'var foo = function() {;"use strict"',
@@ -156,21 +156,24 @@ describe("Directives", function() {
});
});
});
it("Should test EXPECT_DIRECTIVE RegExp", function() {
it("Should print semicolon to separate strings from directives", function() {
[
[ "", true ],
[ "'test';", true ],
[ "'test';;", true ],
[ "'tests';\n", true ],
[ "'tests'", false ],
[ "'tests'; \n\t", true ],
[ "'tests';\n\n", true ],
[ "\n\n\"use strict\";\n\n", true ],
[ "", ';"";' ],
[ '"test";', '"test";;"";' ],
[ '"test";;', '"test";;"";' ],
[ '"tests";\n', '"tests";;"";' ],
[ '"tests"', '"tests";;"";' ],
[ '"tests"; \n\t', '"tests";;"";' ],
[ '"tests";\n\n', '"tests";;"";' ],
[ '\n\n"use strict";\n\n', '"use strict";;"";' ],
].forEach(function(test) {
var ast = UglifyJS.parse(test[0]);
ast.body.push(new UglifyJS.AST_SimpleStatement({
body: new UglifyJS.AST_String({ value: "" })
}));
var out = UglifyJS.OutputStream();
out.print(test[0]);
out.print_string("", null, true);
assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]);
ast.print(out);
assert.strictEqual(out.get(), test[1], test[0]);
});
});
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
@@ -178,8 +181,8 @@ describe("Directives", function() {
'"use strict";',
"'use strict';",
'"use strict";',
'"use strict";;',
"'use strict';",
'"use strict";',
";'use strict';",
"console.log('use strict');"
].join(""), {
compress: false,
@@ -201,19 +204,23 @@ describe("Directives", function() {
it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() {
[
[
'{"use\x20strict"}',
'"use strict";"use\\x20strict";',
'"use strict";"use\\x20strict";'
],
[
'{"use\\x20strict"}',
'{"use strict"}'
],
[
'function foo(){"use\x20strict";}', // Valid place for directives
'function foo(){"use strict"}'
'function foo(){"use\\x20strict";}', // Valid place for directives
'function foo(){"use\\x20strict"}'
],
[
'try{"use\x20strict"}catch(e){}finally{"use\x20strict"}',
'try{"use\\x20strict"}catch(e){}finally{"use\\x20strict"}',
'try{"use strict"}catch(e){}finally{"use strict"}'
],
[
'if(1){"use\x20strict"} else {"use strict"}',
'if(1){"use\\x20strict"} else {"use strict"}',
'if(1){"use strict"}else{"use strict"}'
]
].forEach(function(test) {
@@ -225,16 +232,6 @@ describe("Directives", function() {
assert.strictEqual(result.code, test[1], test[0]);
});
});
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
var result = UglifyJS.minify('"use strict";"use\\x20strict";', {
compress: false,
output: {
semicolons: false
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '"use strict";;"use strict"\n');
});
it("Should check quote style of directives", function() {
[
// 0. Prefer double quotes, unless string contains more double quotes than single quotes
@@ -249,9 +246,9 @@ describe("Directives", function() {
'"use strict";'
],
[
'"\\\'use strict\\\'";', // Not a directive as it contains quotes
'"\\\'use strict\\\'";',
0,
';"\'use strict\'";',
'"\\\'use strict\\\'";',
],
[
"'\"use strict\"';",
@@ -273,7 +270,7 @@ describe("Directives", function() {
'"\'use strict\'";',
1,
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
"'\\'use strict\\'';",
'"\'use strict\'";',
],
[
"'\\'use strict\\'';", // Not a valid directive
@@ -305,7 +302,7 @@ describe("Directives", function() {
"'\"use strict\"';",
2,
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
'"\\\"use strict\\\"";',
"'\"use strict\"';",
],
[
'"\\"use strict\\"";', // Not a valid directive
@@ -353,8 +350,7 @@ describe("Directives", function() {
[
// Nothing gets optimised in the compressor because "use asm" is the first statement
'"use asm";"use\\x20strict";1+1;',
// Yet, the parser noticed that "use strict" wasn't a directive
'"use asm";;"use strict";1+1;',
'"use asm";"use\\x20strict";1+1;'
],
[
'function f(){ "use strict" }',

View File

@@ -51,7 +51,7 @@ describe("minify", function() {
"var a=n(3),b=r(12);",
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should work with nameCache", function() {
@@ -84,7 +84,7 @@ describe("minify", function() {
"var a=n(3),b=r(12);",
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should avoid cached names when mangling top-level variables", function() {
@@ -113,7 +113,7 @@ describe("minify", function() {
'"xxyyy";var y={y:2,a:3},a=4;',
'console.log(x.x,y.y,y.a,a);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should avoid cached names when mangling inner-scoped variables", function() {
@@ -137,7 +137,7 @@ describe("minify", function() {
'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should not parse invalid use of reserved words", function() {

View File

@@ -2,10 +2,18 @@ var assert = require("assert");
var UglifyJS = require("../node");
describe("Number literals", function() {
it("Should allow legacy octal literals in non-strict mode", function() {
[
"'use strict'\n.slice()\n00",
'"use strict"\n.slice()\nvar foo = 00',
].forEach(function(input) {
UglifyJS.parse(input);
});
});
it("Should not allow legacy octal literals in strict mode", function() {
var inputs = [
'"use strict";00;',
'"use strict"; var foo = 00;'
'"use strict"; var foo = 00;',
];
var test = function(input) {
return function() {

249
test/mocha/reduce.js Normal file
View File

@@ -0,0 +1,249 @@
var assert = require("assert");
var exec = require("child_process").exec;
var fs = require("fs");
var reduce_test = require("../reduce");
var semver = require("semver");
function read(path) {
return fs.readFileSync(path, "utf8");
}
describe("test/reduce.js", function() {
this.timeout(60000);
it("Should reduce test case", function() {
var result = reduce_test(read("test/input/reduce/unsafe_math.js"), {
compress: {
unsafe_math: true,
},
mangle: false,
}, {
verbose: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/unsafe_math.reduced.js"));
});
it("Should eliminate unreferenced labels", function() {
var result = reduce_test(read("test/input/reduce/label.js"), {
mangle: false,
}, {
verbose: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/label.reduced.js"));
});
it("Should retain setter arguments", function() {
var result = reduce_test(read("test/input/reduce/setter.js"), {
compress: {
keep_fargs: false,
unsafe: true,
},
mangle: false,
}, {
verbose: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/setter.reduced.js"));
});
it("Should handle test cases with --toplevel", function() {
var result = reduce_test([
"var Infinity = 42;",
"console.log(Infinity);",
].join("\n"), {
toplevel: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "toplevel": true',
"// }",
].join("\n"));
});
it("Should handle test cases with --compress toplevel", function() {
var result = reduce_test([
"var NaN = 42;",
"console.log(NaN);",
].join("\n"), {
compress: {
toplevel: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "compress": {',
'// "toplevel": true',
"// }",
"// }",
].join("\n"));
});
it("Should handle test cases with --mangle toplevel", function() {
var result = reduce_test([
"var undefined = 42;",
"console.log(undefined);",
].join("\n"), {
mangle: {
toplevel: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {",
'// "mangle": {',
'// "toplevel": true',
"// }",
"// }",
].join("\n"));
});
it("Should handle test result of NaN", function() {
var result = reduce_test("throw 0 / 0;");
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// Can't reproduce test failure",
"// minify options: {}",
].join("\n"));
});
it("Should print correct output for irreducible test case", function() {
var result = reduce_test([
"console.log(function f(a) {",
" return f.length;",
"}());",
].join("\n"), {
compress: {
keep_fargs: false,
},
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// (beautified)",
"console.log(function f(a) {",
" return f.length;",
"}());",
"// output: 1",
"// ",
"// minify: 0",
"// ",
"// options: {",
'// "compress": {',
'// "keep_fargs": false',
"// },",
'// "mangle": false',
"// }",
].join("\n"));
});
it("Should fail when invalid option is supplied", function() {
var result = reduce_test("", {
compress: {
unsafe_regex: true,
},
});
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "DefaultsError: `unsafe_regex` is not a supported option");
});
it("Should report on test case with invalid syntax", function() {
var result = reduce_test("var 0 = 1;");
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Name expected");
});
it("Should format multi-line output correctly", function() {
var code = [
"var a = 0;",
"",
"for (var b in [ 1, 2, 3 ]) {",
" a = +a + 1 - .2;",
" console.log(a);",
"}",
].join("\n");
var result = reduce_test(code, {
compress: {
unsafe_math: true,
},
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// (beautified)",
code,
"// output: 0.8",
"// 1.6",
"// 2.4",
"// ",
"// minify: 0.8",
"// 1.6",
"// 2.4000000000000004",
"// ",
"// options: {",
'// "compress": {',
'// "unsafe_math": true',
"// },",
'// "mangle": false',
"// }",
].join("\n"));
});
it("Should reduce infinite loops with reasonable performance", function() {
if (semver.satisfies(process.version, "<=0.10")) return;
this.timeout(120000);
var result = reduce_test("while (/9/.test(1 - .8));", {
compress: {
unsafe_math: true,
},
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code.replace(/ timed out after [0-9]+ms/, " timed out."), [
"// (beautified)",
"while (/9/.test(1 - .8)) {}",
"// output: Error: Script execution timed out.",
"// minify: ",
"// options: {",
'// "compress": {',
'// "unsafe_math": true',
"// },",
'// "mangle": false',
"// }",
].join("\n"));
});
it("Should ignore difference in Error.message", function() {
var result = reduce_test("null[function() {\n}];");
if (result.error) throw result.error;
assert.strictEqual(result.code, (semver.satisfies(process.version, "<=0.10") ? [
"// Can't reproduce test failure",
"// minify options: {}",
] : [
"// No differences except in error message",
"// minify options: {}",
]).join("\n"));
});
it("Should report trailing whitespace difference in stringified format", function() {
var code = [
"for (var a in (1 - .8).toString()) {",
" console.log();",
"}",
].join("\n");
var result = reduce_test(code, {
compress: {
unsafe_math: true,
},
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// (beautified)",
code,
"// (stringified)",
'// output: "\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"',
'// minify: "\\n\\n\\n"',
"// options: {",
'// "compress": {',
'// "unsafe_math": true',
'// },',
'// "mangle": false',
"// }",
].join("\n"));
});
});

View File

@@ -1,10 +1,9 @@
var assert = require("assert");
var readFileSync = require("fs").readFileSync;
var SourceMapConsumer = require("source-map").SourceMapConsumer;
var UglifyJS = require("../..");
var fs = require("fs");
var UglifyJS = require("../node");
function read(path) {
return readFileSync(path, "utf8");
return fs.readFileSync(path, "utf8");
}
function source_map(code) {
@@ -44,7 +43,7 @@ function prepare_map(sourceMap) {
}
});
if (result.error) throw result.error;
return new SourceMapConsumer(result.map);
return JSON.parse(result.map);
}
describe("sourcemaps", function() {
@@ -87,14 +86,30 @@ describe("sourcemaps", function() {
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI","sourceRoot":"//foo.bar/"}');
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI"}');
});
it("Should produce same source map with DOS or UNIX line endings", function() {
var code = [
'console.log("\\',
'hello",',
'"world");',
];
var dos = UglifyJS.minify(code.join("\r\n"), {
sourceMap: true,
});
if (dos.error) throw dos.error;
var unix = UglifyJS.minify(code.join("\n"), {
sourceMap: true,
});
if (unix.error) throw unix.error;
assert.strictEqual(dos.map, unix.map);
});
describe("inSourceMap", function() {
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", function() {
var result = UglifyJS.minify(read("./test/input/issue-1236/simple.js"), {
var result = UglifyJS.minify(read("test/input/issue-1236/simple.js"), {
sourceMap: {
content: read("./test/input/issue-1236/simple.js.map"),
content: read("test/input/issue-1236/simple.js.map"),
filename: "simple.min.js",
includeSources: true
}
@@ -106,7 +121,7 @@ describe("sourcemaps", function() {
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
});
it("Should process inline source map", function() {
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
@@ -115,10 +130,10 @@ describe("sourcemaps", function() {
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
});
it("Should warn for missing inline source map", function() {
var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), {
var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
mangle: false,
sourceMap: {
content: "inline"
@@ -130,8 +145,8 @@ describe("sourcemaps", function() {
});
it("Should handle multiple input and inline source map", function() {
var result = UglifyJS.minify([
read("./test/input/issue-520/input.js"),
read("./test/input/issue-1323/sample.js"),
read("test/input/issue-520/input.js"),
read("test/input/issue-1323/sample.js"),
], {
sourceMap: {
content: "inline",
@@ -147,7 +162,7 @@ describe("sourcemaps", function() {
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
});
it("Should drop source contents for includeSources=false", function() {
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: false,
mangle: false,
sourceMap: {
@@ -170,7 +185,7 @@ describe("sourcemaps", function() {
assert.ok(!("sourcesContent" in map));
});
it("Should parse the correct sourceMappingURL", function() {
var result = UglifyJS.minify(read("./test/input/issue-3294/input.js"), {
var result = UglifyJS.minify(read("test/input/issue-3294/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
@@ -179,7 +194,19 @@ describe("sourcemaps", function() {
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8"));
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
});
it("Should work in presence of unrecognised annotations", function() {
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false,
mangle: false,
sourceMap: {
content: "inline",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){console.log("hello")}).call(this);');
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI"}');
});
});
@@ -202,7 +229,7 @@ describe("sourcemaps", function() {
assert.strictEqual(code, "var a=function(n){return n};");
});
it("Should work with max_line_len", function() {
var result = UglifyJS.minify(read("./test/input/issue-505/input.js"), {
var result = UglifyJS.minify(read("test/input/issue-505/input.js"), {
compress: {
directives: false,
},
@@ -214,7 +241,7 @@ describe("sourcemaps", function() {
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
});
it("Should work with unicode characters", function() {
var code = [
@@ -232,7 +259,7 @@ describe("sourcemaps", function() {
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
var encoded = result.code.slice(result.code.lastIndexOf(",") + 1);
map = JSON.parse(new Buffer(encoded, "base64").toString());
map = JSON.parse(UglifyJS.to_ascii(encoded));
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
result = UglifyJS.minify(result.code, {
@@ -250,32 +277,42 @@ describe("sourcemaps", function() {
});
describe("input sourcemaps", function() {
it("Should not modify input source map", function() {
var orig = get_map();
var original = JSON.stringify(orig);
var map = prepare_map(orig);
assert.strictEqual(JSON.stringify(orig), original);
});
it("Should copy over original sourcesContent", function() {
var orig = get_map();
var map = prepare_map(orig);
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
assert.strictEqual(map.sources.length, 1);
assert.strictEqual(map.sources[0], "index.js");
assert.strictEqual(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], orig.sourcesContent[0]);
});
it("Should copy sourcesContent if sources are relative", function() {
var relativeMap = get_map();
relativeMap.sources = ['./index.js'];
var map = prepare_map(relativeMap);
assert.notEqual(map.sourcesContent, null);
assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
assert.strictEqual(map.sources.length, 1);
assert.strictEqual(map.sources[0], "./index.js");
assert.strictEqual(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], relativeMap.sourcesContent[0]);
});
it("Should not have invalid mappings from inputSourceMap", function() {
var map = prepare_map(get_map());
// The original source has only 2 lines, check that mappings don't have more lines
var msg = "Mapping should not have higher line number than the original file had";
map.eachMapping(function(mapping) {
assert.ok(mapping.originalLine <= 2, msg);
});
map.allGeneratedPositionsFor({
source: "index.js",
line: 1,
column: 1
}).forEach(function(pos) {
assert.ok(pos.line <= 2, msg);
var lines = map.mappings.split(/;/);
assert.ok(lines.length <= 2, msg);
var indices = [ 0, 0, 1, 0, 0];
lines.forEach(function(segments) {
indices[0] = 0;
segments.split(/,/).forEach(function(segment) {
UglifyJS.vlq_decode(indices, segment);
assert.ok(indices[2] <= 2, msg);
});
});
});
});

View File

@@ -10,7 +10,9 @@ describe("spidermonkey export/import sanity test", function() {
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
uglifyjs + " -p spidermonkey -cm";
exec(command, function(err, stdout) {
exec(command, {
maxBuffer: 1048576
}, function(err, stdout) {
if (err) throw err;
eval(stdout);

View File

@@ -59,13 +59,13 @@ describe("String literals", function() {
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
var tests = [
['"\\76";', ';">";'],
['"\\0"', '"\\0";'],
['"\\08"', '"\\x008";'],
['"\\008"', '"\\x008";'],
['"\\0008"', '"\\x008";'],
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
[ ';"\\76";', ';">";' ],
[ ';"\\0";', ';"\\0";' ],
[ ';"\\08"', ';"\\x008";' ],
[ ';"\\008"', ';"\\x008";' ],
[ ';"\\0008"', ';"\\x008";' ],
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
];
for (var test in tests) {
@@ -75,8 +75,8 @@ describe("String literals", function() {
});
it("Should not throw error when digit is 8 or 9", function() {
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
});
it("Should not unescape unpaired surrogates", function() {
@@ -93,7 +93,7 @@ describe("String literals", function() {
for (; i <= 0xFFFF; i++) {
code.push("\\u" + i.toString(16));
}
code = '"' + code.join() + '"';
code = ';"' + code.join() + '"';
var normal = UglifyJS.minify(code, {
compress: false,
mangle: false,

View File

@@ -44,30 +44,37 @@ function test(original, estree, description) {
try_beautify(transformed.code);
}
console.log("!!!!!! Failed... round", round);
process.exit(1);
return false;
}
return true;
}
var num_iterations = ufuzz.num_iterations;
var minify_options = require("./ufuzz/options.json").map(JSON.stringify);
minify_options.unshift(null);
for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r");
var code = ufuzz.createTopLevelCode();
var uglified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
minify_options.forEach(function(options) {
var input = options ? UglifyJS.minify(code, JSON.parse(options)).code : code;
var uglified = UglifyJS.minify(input, {
compress: false,
mangle: false,
output: {
ast: true
}
});
var ok = test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
try {
ok = test(uglified.code, acorn.parse(input), "acorn.parse()") && ok;
} catch (e) {
console.log("//=============================================================");
console.log("// acorn parser failed... round", round);
console.log(e);
console.log("// original code");
console.log(input);
}
if (!ok) process.exit(1);
});
test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
try {
test(uglified.code, acorn.parse(code), "acorn.parse()");
} catch (e) {
console.log("//=============================================================");
console.log("// acorn parser failed... round", round);
console.log(e);
console.log("// original code");
console.log(code);
}
}
console.log();

View File

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

622
test/reduce.js Normal file
View File

@@ -0,0 +1,622 @@
var crypto = require("crypto");
var U = require("./node");
var List = U.List;
var os = require("os");
var sandbox = require("./sandbox");
// Reduce a ufuzz-style `console.log` based test case by iteratively replacing
// AST nodes with various permutations. Each AST_Statement in the tree is also
// speculatively dropped to determine whether it is needed. If the altered
// tree and the last known good tree produce the same non-nil error-free output
// after being run, then the permutation survives to the next generation and
// is the basis for subsequent iterations. The test case is reduced as a
// consequence of complex expressions being replaced with simpler ones.
// This function assumes that the testcase will not result in a parse or
// runtime Error. Note that a reduced test case will have different runtime
// output - it is not functionally equivalent to the original. The only criteria
// is that once the generated reduced test case is run without minification, it
// will produce different output from the code minified with `minify_options`.
// Returns a `minify` result object with an additonal boolean property `reduced`.
module.exports = function reduce_test(testcase, minify_options, reduce_options) {
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string();
minify_options = minify_options || {};
reduce_options = reduce_options || {};
var max_iterations = reduce_options.max_iterations || 1000;
var max_timeout = reduce_options.max_timeout || 10000;
var verbose = reduce_options.verbose;
var minify_options_json = JSON.stringify(minify_options, null, 2);
var result_cache = Object.create(null);
// the initial timeout to assess the viability of the test case must be large
var differs = producesDifferentResultWhenMinified(result_cache, testcase, minify_options, max_timeout);
if (verbose) {
console.error("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
}
if (!differs) {
// same stdout result produced when minified
return {
code: [
"// Can't reproduce test failure",
"// minify options: " + to_comment(minify_options_json)
].join("\n")
};
} else if (differs.timed_out) {
return {
code: [
"// Can't reproduce test failure within " + max_timeout + "ms",
"// minify options: " + to_comment(minify_options_json)
].join("\n")
};
} else if (differs.error) {
return differs;
} else if (is_error(differs.unminified_result)
&& is_error(differs.minified_result)
&& differs.unminified_result.name == differs.minified_result.name) {
return {
code: [
"// No differences except in error message",
"// minify options: " + to_comment(minify_options_json)
].join("\n")
};
} else {
max_timeout = Math.min(100 * differs.elapsed, max_timeout);
// Replace expressions with constants that will be parsed into
// AST_Nodes as required. Each AST_Node has its own permutation count,
// so these replacements can't be shared.
// Although simpler replacements are generally faster and better,
// feel free to experiment with a different replacement set.
var REPLACEMENTS = [
// "null", "''", "false", "'foo'", "undefined", "9",
"1", "0",
];
// There's a relationship between each node's _permute counter and
// REPLACEMENTS.length which is why fractional _permutes were needed.
// One could scale all _permute operations by a factor of `steps`
// to only deal with integer operations, but this works well enough.
var steps = 4; // must be a power of 2
var step = 1 / steps; // 0.25 is exactly representable in floating point
var tt = new U.TreeTransformer(function(node, descend, in_list) {
if (CHANGED) return;
// quick ignores
if (node instanceof U.AST_Accessor) return;
if (node instanceof U.AST_Directive) return;
if (!in_list && node instanceof U.AST_EmptyStatement) return;
if (node instanceof U.AST_Label) return;
if (node instanceof U.AST_LabelRef) return;
if (!in_list && node instanceof U.AST_SymbolDeclaration) return;
if (node instanceof U.AST_Toplevel) return;
var parent = tt.parent();
if (node instanceof U.AST_SymbolFunarg && parent instanceof U.AST_Accessor) return;
// ensure that the _permute prop is a number.
// can not use `node.start._permute |= 0;` as it will erase fractional part.
if (typeof node.start._permute === "undefined") node.start._permute = 0;
// if node reached permutation limit - skip over it.
// no structural AST changes before this point.
if (node.start._permute >= REPLACEMENTS.length) return;
if (parent instanceof U.AST_Assign
&& parent.left === node
|| parent instanceof U.AST_Unary
&& parent.expression === node
&& ["++", "--", "delete"].indexOf(parent.operator) >= 0) {
// ignore lvalues
return;
}
if ((parent instanceof U.AST_For || parent instanceof U.AST_ForIn)
&& parent.init === node && node instanceof U.AST_Var) {
// preserve for (var ...)
return node;
}
// node specific permutations with no parent logic
if (node instanceof U.AST_Array) {
var expr = node.elements[0];
if (expr && !(expr instanceof U.AST_Hole)) {
node.start._permute++;
CHANGED = true;
return expr;
}
}
else if (node instanceof U.AST_Binary) {
CHANGED = true;
var permute = ((node.start._permute += step) * steps | 0) % 4;
var expr = [
node.left,
node.right,
][ permute & 1 ];
if (permute < 2) return expr;
// wrap with console.log()
return new U.AST_Call({
expression: new U.AST_Dot({
expression: new U.AST_SymbolRef({
name: "console",
start: {},
}),
property: "log",
start: {},
}),
args: [ expr ],
start: {},
});
}
else if (node instanceof U.AST_Catch || node instanceof U.AST_Finally) {
// drop catch or finally block
node.start._permute++;
CHANGED = true;
return null;
}
else if (node instanceof U.AST_Conditional) {
CHANGED = true;
return [
node.condition,
node.consequent,
node.alternative,
][ ((node.start._permute += step) * steps | 0) % 3 ];
}
else if (node instanceof U.AST_BlockStatement) {
if (in_list) {
node.start._permute++;
CHANGED = true;
return List.splice(node.body);
}
}
else if (node instanceof U.AST_Call) {
var expr = [
node.expression,
node.args[0],
null, // intentional
][ ((node.start._permute += step) * steps | 0) % 3 ];
if (expr) {
CHANGED = true;
return expr;
}
if (node.expression instanceof U.AST_Function) {
// hoist and return expressions from the IIFE function expression
var body = node.expression.body;
node.expression.body = [];
var seq = [];
body.forEach(function(node) {
var expr = expr instanceof U.AST_Exit ? node.value : node.body;
if (expr instanceof U.AST_Node && !is_statement(expr)) {
// collect expressions from each statements' body
seq.push(expr);
}
});
CHANGED = true;
return to_sequence(seq);
}
}
else if (node instanceof U.AST_Defun) {
switch (((node.start._permute += step) * steps | 0) % 2) {
case 0:
CHANGED = true;
return List.skip;
case 1:
if (!has_exit(node)) {
// hoist function declaration body
var body = node.body;
node.body = [];
body.push(node); // retain function with empty body to be dropped later
CHANGED = true;
return List.splice(body);
}
}
}
else if (node instanceof U.AST_DWLoop) {
var expr = [
node.condition,
node.body,
null, // intentional
][ (node.start._permute * steps | 0) % 3 ];
node.start._permute += step;
if (!expr) {
if (node.body[0] instanceof U.AST_Break) {
if (node instanceof U.AST_Do) {
CHANGED = true;
return List.skip;
}
expr = node.condition; // AST_While - fall through
}
}
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
CHANGED = true;
return to_statement(expr);
}
}
else if (node instanceof U.AST_PropAccess) {
var expr = [
node.expression,
node.property instanceof U.AST_Node && node.property,
][ node.start._permute++ % 2 ];
if (expr) {
CHANGED = true;
return expr;
}
}
else if (node instanceof U.AST_For) {
var expr = [
node.init,
node.condition,
node.step,
node.body,
][ (node.start._permute * steps | 0) % 4 ];
node.start._permute += step;
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
CHANGED = true;
return to_statement(expr);
}
}
else if (node instanceof U.AST_ForIn) {
var expr = [
node.init,
node.object,
node.body,
][ (node.start._permute * steps | 0) % 3 ];
node.start._permute += step;
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
CHANGED = true;
return to_statement(expr);
}
}
else if (node instanceof U.AST_If) {
var expr = [
node.condition,
node.body,
node.alternative,
][ (node.start._permute * steps | 0) % 3 ];
node.start._permute += step;
if (expr) {
// replace if statement with its condition, then block or else block
CHANGED = true;
return to_statement(expr);
}
}
else if (node instanceof U.AST_Object) {
// first property's value
var expr = node.properties[0] instanceof U.AST_ObjectKeyVal && node.properties[0].value;
if (expr) {
node.start._permute++;
CHANGED = true;
return expr;
}
}
else if (node instanceof U.AST_SimpleStatement) {
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
// hoist simple statement IIFE function expression body
node.start._permute++;
if (!has_exit(node.body.expression)) {
var body = node.body.expression.body;
node.body.expression.body = [];
CHANGED = true;
return List.splice(body);
}
}
}
else if (node instanceof U.AST_Switch) {
var expr = [
node.expression, // switch expression
node.body[0] && node.body[0].expression, // first case expression or undefined
node.body[0] && node.body[0], // first case body or undefined
][ (node.start._permute * steps | 0) % 4 ];
node.start._permute += step;
if (expr && (!(expr instanceof U.AST_Statement) || !has_loopcontrol(expr, node, parent))) {
CHANGED = true;
return expr instanceof U.AST_SwitchBranch ? new U.AST_BlockStatement({
body: expr.body.slice(),
start: {},
}) : to_statement(expr);
}
}
else if (node instanceof U.AST_Try) {
var body = [
node.body,
node.bcatch && node.bcatch.body,
node.bfinally && node.bfinally.body,
null, // intentional
][ (node.start._permute * steps | 0) % 4 ];
node.start._permute += step;
if (body) {
// replace try statement with try block, catch block, or finally block
CHANGED = true;
return new U.AST_BlockStatement({
body: body,
start: {},
});
} else {
// replace try with a break or return if first in try statement
if (node.body[0] instanceof U.AST_Break
|| node.body[0] instanceof U.AST_Return) {
CHANGED = true;
return node.body[0];
}
}
}
else if (node instanceof U.AST_Unary) {
node.start._permute++;
CHANGED = true;
return node.expression;
}
else if (node instanceof U.AST_Var) {
if (node.definitions.length == 1 && node.definitions[0].value) {
// first declaration value
node.start._permute++;
CHANGED = true;
return to_statement(node.definitions[0].value);
}
}
else if (node instanceof U.AST_LabeledStatement) {
if (node.body instanceof U.AST_Statement
&& !has_loopcontrol(node.body, node.body, node)) {
// replace labelled statement with its non-labelled body
node.start._permute = REPLACEMENTS.length;
CHANGED = true;
return node.body;
}
}
if (in_list) {
// special case to drop object properties and switch branches
if (parent instanceof U.AST_Object
|| parent instanceof U.AST_Switch && parent.expression != node) {
node.start._permute++;
CHANGED = true;
return List.skip;
}
// replace or skip statement
if (node instanceof U.AST_Statement) {
node.start._permute++;
CHANGED = true;
return List.skip;
}
// remove this node unless its the sole element of a (transient) sequence
if (!(parent instanceof U.AST_Sequence) || parent.expressions.length > 1) {
node.start._permute++;
CHANGED = true;
return List.skip;
}
}
// replace this node
var newNode = is_statement(node) ? new U.AST_EmptyStatement({
start: {},
}) : U.parse(REPLACEMENTS[node.start._permute % REPLACEMENTS.length | 0], {
expression: true,
});
newNode.start._permute = ++node.start._permute;
CHANGED = true;
return newNode;
}, function(node, in_list) {
if (node instanceof U.AST_Sequence) {
// expand single-element sequence
if (node.expressions.length == 1) return node.expressions[0];
}
else if (node instanceof U.AST_Try) {
// expand orphaned try block
if (!node.bcatch && !node.bfinally) return new U.AST_BlockStatement({
body: node.body,
start: {},
});
}
else if (node instanceof U.AST_Var) {
// remove empty var statement
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
start: {},
});
}
});
for (var pass = 1; pass <= 3; ++pass) {
var testcase_ast = U.parse(testcase);
testcase_ast.walk(new U.TreeWalker(function(node) {
// unshare start props to retain visit data between iterations
node.start = JSON.parse(JSON.stringify(node.start));
node.start._permute = 0;
}));
for (var c = 0; c < max_iterations; ++c) {
if (verbose) {
if (pass == 1 && c % 25 == 0) {
console.error("// reduce test pass "
+ pass + ", iteration " + c + ": " + testcase.length + " bytes");
}
}
var CHANGED = false;
var code_ast = testcase_ast.clone(true).transform(tt);
if (!CHANGED) break;
try {
var code = code_ast.print_to_string();
} catch (ex) {
// AST is not well formed.
// no harm done - just log the error, ignore latest change and continue iterating.
console.error("*** Error generating code from AST.");
console.error(ex);
console.error("*** Discarding permutation and continuing.");
continue;
}
var diff = producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout);
if (diff) {
if (diff.timed_out) {
// can't trust the validity of `code_ast` and `code` when timed out.
// no harm done - just ignore latest change and continue iterating.
} else if (diff.error) {
// something went wrong during minify() - could be malformed AST or genuine bug.
// no harm done - just log code & error, ignore latest change and continue iterating.
console.error("*** Error during minification.");
console.error(code);
console.error(diff.error);
console.error("*** Discarding permutation and continuing.");
} else if (is_error(diff.unminified_result)
&& is_error(diff.minified_result)
&& diff.unminified_result.name == diff.minified_result.name) {
// ignore difference in error messages caused by minification
} else {
// latest permutation is valid, so use it as the basis of new changes
testcase_ast = code_ast;
testcase = code;
differs = diff;
}
}
}
if (c == 0) break;
if (verbose) {
console.error("// reduce test pass " + pass + ": " + testcase.length + " bytes");
}
}
testcase = try_beautify(result_cache, testcase, minify_options, differs.unminified_result, max_timeout);
var lines = [ "" ];
var unminified_result = strip_color_codes(differs.unminified_result);
var minified_result = strip_color_codes(differs.minified_result);
if (trim_trailing_whitespace(unminified_result) == trim_trailing_whitespace(minified_result)) {
lines.push(
"// (stringified)",
"// output: " + JSON.stringify(unminified_result),
"// minify: " + JSON.stringify(minified_result)
);
} else {
lines.push(
"// output: " + to_comment(unminified_result),
"// minify: " + to_comment(minified_result)
);
}
lines.push("// options: " + to_comment(minify_options_json));
testcase.code += lines.join("\n");
return testcase;
}
};
function strip_color_codes(value) {
return ("" + value).replace(/\u001b\[\d+m/g, "");
}
function to_comment(value) {
return ("" + value).replace(/\n/g, "\n// ");
}
function trim_trailing_whitespace(value) {
return ("" + value).replace(/\s+$/, "");
}
function try_beautify(result_cache, testcase, minify_options, expected, timeout) {
var result = U.minify(testcase, {
compress: false,
mangle: false,
output: {
beautify: true,
braces: true,
comments: true,
},
});
if (result.error) return {
code: testcase,
};
var toplevel = sandbox.has_toplevel(minify_options);
var actual = run_code(result_cache, result.code, toplevel, timeout);
if (!sandbox.same_stdout(expected, actual)) return {
code: testcase,
};
result.code = "// (beautified)\n" + result.code;
return result;
}
function has_exit(fn) {
var found = false;
var tw = new U.TreeWalker(function(node) {
if (found) return found;
if (node instanceof U.AST_Exit) {
return found = true;
}
if (node instanceof U.AST_Scope && node !== fn) {
return true; // don't descend into nested functions
}
});
fn.walk(tw);
return found;
}
function has_loopcontrol(body, loop, label) {
var found = false;
var tw = new U.TreeWalker(function(node) {
if (found) return true;
if (node instanceof U.AST_LoopControl && this.loopcontrol_target(node) === loop) {
return found = true;
}
});
if (label instanceof U.AST_LabeledStatement) tw.push(label);
tw.push(loop);
body.walk(tw);
return found;
}
function is_error(result) {
return typeof result == "object" && typeof result.name == "string" && typeof result.message == "string";
}
function is_timed_out(result) {
return is_error(result) && /timed out/.test(result);
}
function is_statement(node) {
return node instanceof U.AST_Statement && !(node instanceof U.AST_Function);
}
function merge_sequence(array, node) {
if (node instanceof U.AST_Sequence) {
array.push.apply(array, node.expressions);
} else {
array.push(node);
}
return array;
}
function to_sequence(expressions) {
if (expressions.length == 0) return new U.AST_Number({value: 0, start: {}});
if (expressions.length == 1) return expressions[0];
return new U.AST_Sequence({
expressions: expressions.reduce(merge_sequence, []),
start: {},
});
}
function to_statement(node) {
return is_statement(node) ? node : new U.AST_SimpleStatement({
body: node,
start: {},
});
}
function run_code(result_cache, code, toplevel, timeout) {
var key = crypto.createHash("sha1").update(code).digest("base64");
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
}
function producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout) {
var minified = U.minify(code, minify_options);
if (minified.error) return minified;
var toplevel = sandbox.has_toplevel(minify_options);
var elapsed = Date.now();
var unminified_result = run_code(result_cache, code, toplevel, max_timeout);
elapsed = Date.now() - elapsed;
var timeout = Math.min(100 * elapsed, max_timeout);
var minified_result = run_code(result_cache, minified.code, toplevel, timeout);
if (sandbox.same_stdout(unminified_result, minified_result)) {
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
timed_out: true,
};
}
return {
unminified_result: unminified_result,
minified_result: minified_result,
elapsed: elapsed,
};
}
Error.stackTraceLimit = Infinity;

View File

@@ -54,14 +54,15 @@ function createContext() {
}
}
exports.run_code = function(code, toplevel) {
exports.run_code = function(code, toplevel, timeout) {
timeout = timeout || 5000;
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: 5000 });
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: timeout });
return stdout;
} catch (ex) {
return ex;
@@ -76,8 +77,9 @@ function strip_func_ids(text) {
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected != "string") {
if (expected.name != actual.name) return false;
if (typeof expected == "object" && typeof expected.name == "string" && typeof expected.message == "string") {
if (expected.name !== actual.name) return false;
if (typeof actual.message != "string") return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
}
@@ -85,3 +87,8 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
} : function(expected, actual) {
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
};
exports.has_toplevel = function(options) {
return options.toplevel
|| options.mangle && options.mangle.toplevel
|| options.compress && options.compress.toplevel;
};

View File

@@ -1,81 +0,0 @@
"use strict";
var child_process = require("child_process");
var https = require("https");
var url = require("url");
var period = 45 * 60 * 1000;
var wait = 2 * 60 * 1000;
var ping = 5 * 60 * 1000;
if (process.argv[2] == "run") {
var endTime = Date.now() + period;
for (var i = 0; i < 2; i++) spawn(endTime);
} else if (process.argv.length > 2) {
var token = process.argv[2];
var branch = process.argv[3] || "v" + require("../package.json").version;
var repository = encodeURIComponent(process.argv[4] || "mishoo/UglifyJS2");
var concurrency = process.argv[5] || 1;
var platform = process.argv[6] || "node/latest";
(function request() {
setTimeout(request, (period + wait) / concurrency);
var options = url.parse("https://api.travis-ci.org/repo/" + repository + "/requests");
options.method = "POST";
options.headers = {
"Content-Type": "application/json",
"Travis-API-Version": 3,
"Authorization": "token " + token
};
https.request(options, function(res) {
console.log("HTTP", res.statusCode);
console.log(JSON.stringify(res.headers, null, 2));
console.log();
res.setEncoding("utf8");
res.on("data", console.log);
}).on("error", console.error).end(JSON.stringify({
request: {
message: "ufuzz testing",
branch: branch,
config: {
cache: false,
env: "NODEJS_VER=" + platform,
script: "node test/travis-ufuzz run"
}
}
}));
})();
} else {
console.log("Usage: test/travis-ufuzz.js <token> [branch] [repository] [concurrency] [platform]");
}
function spawn(endTime) {
var child = child_process.spawn("node", [
"--max-old-space-size=2048",
"test/ufuzz"
], {
stdio: [ "ignore", "pipe", "pipe" ]
}).on("exit", respawn);
var line = "";
child.stdout.on("data", function(data) {
line += data;
});
child.stderr.on("data", function() {
process.exitCode = 1;
}).pipe(process.stdout);
var keepAlive = setInterval(function() {
var end = line.lastIndexOf("\r");
console.log(line.slice(line.lastIndexOf("\r", end - 1) + 1, end));
line = line.slice(end + 1);
}, ping);
var timer = setTimeout(function() {
clearInterval(keepAlive);
child.removeListener("exit", respawn);
child.kill();
}, endTime - Date.now());
function respawn() {
console.log(line);
clearInterval(keepAlive);
clearTimeout(timer);
spawn(endTime);
}
}

File diff suppressed because it is too large Load Diff

46
test/ufuzz/job.js Normal file
View File

@@ -0,0 +1,46 @@
var child_process = require("child_process");
var ping = 5 * 60 * 1000;
var period = +process.argv[2];
var endTime = Date.now() + period;
for (var i = 0; i < 2; i++) spawn(endTime);
function spawn(endTime) {
var child = child_process.spawn("node", [
"--max-old-space-size=2048",
"test/ufuzz"
], {
stdio: [ "ignore", "pipe", "pipe" ]
}).on("exit", respawn);
var stdout = "";
child.stdout.on("data", function(data) {
stdout += data;
});
var stderr = "";
child.stderr.on("data", trap).pipe(process.stdout);
var keepAlive = setInterval(function() {
var end = stdout.lastIndexOf("\r");
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
stdout = stdout.slice(end + 1);
}, ping);
var timer = setTimeout(function() {
clearInterval(keepAlive);
child.removeListener("exit", respawn);
child.kill();
}, endTime - Date.now());
function respawn() {
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
clearInterval(keepAlive);
clearTimeout(timer);
spawn(endTime);
}
function trap(data) {
stderr += data;
if (~stderr.indexOf("\nminify(options):\n")) {
process.exitCode = 1;
child.stderr.removeListener("data", trap);
}
}
}

View File

@@ -2702,8 +2702,10 @@
"attrChange",
"attrName",
"attributeChangedCallback",
"attributeFilter",
"attributeName",
"attributeNamespace",
"attributeOldValue",
"attributeStyleMap",
"attributes",
"audioTracks",
@@ -3025,6 +3027,8 @@
"charCode",
"charCodeAt",
"charIndex",
"characterData",
"characterDataOldValue",
"characterSet",
"charging",
"chargingTime",
@@ -3036,6 +3040,7 @@
"checkValidity",
"checked",
"childElementCount",
"childList",
"childNodes",
"children",
"chrome",
@@ -6150,6 +6155,7 @@
"substring",
"substringData",
"subtle",
"subtree",
"suffix",
"suffixes",
"summary",

View File

@@ -5,7 +5,7 @@ process.exit = function() {
process.once("uncaughtException", function() {
(function callback() {
if (process.stdout.bufferSize || process.stderr.bufferSize) {
setImmediate(callback);
setTimeout(callback, 1);
} else {
exit.apply(process, args);
}

View File

@@ -1,4 +1,5 @@
exports["Dictionary"] = Dictionary;
exports["List"] = List;
exports["minify"] = minify;
exports["parse"] = parse;
exports["push_uniq"] = push_uniq;

View File

@@ -15,13 +15,13 @@ exports.FILES = [
require.resolve("./exports.js"),
];
new Function("MOZ_SourceMap", "exports", function() {
new Function("exports", function() {
var code = exports.FILES.map(function(file) {
return fs.readFileSync(file, "utf8");
});
code.push("exports.describe_ast = " + describe_ast.toString());
return code.join("\n\n");
}())(require("source-map"), exports);
}())(exports);
function describe_ast() {
var out = OutputStream({ beautify: true });
@@ -46,7 +46,9 @@ function describe_ast() {
if (ctor.SUBCLASSES.length > 0) {
out.space();
out.with_block(function() {
ctor.SUBCLASSES.forEach(function(ctor, i) {
ctor.SUBCLASSES.sort(function(a, b) {
return a.TYPE < b.TYPE ? -1 : 1;
}).forEach(function(ctor, i) {
out.indent();
doitem(ctor);
out.newline();