Compare commits

...

276 Commits

Author SHA1 Message Date
Alex Lam S.L
bba7cd0a70 v3.12.3 2020-12-22 23:59:53 +08:00
Alex Lam S.L
e1b2026929 improve object function generation in ufuzz (#4434) 2020-12-21 15:32:50 +08:00
Alex Lam S.L
c319030373 fix corner case in reduce_vars (#4433)
fixes #4432
2020-12-21 14:03:18 +08:00
Alex Lam S.L
47b63ed1a0 fix corner case in collapse_vars (#4431)
fixes #4430
2020-12-20 22:54:27 +08:00
Alex Lam S.L
7aefe97083 parse destructuring under strict mode correctly (#4429) 2020-12-20 20:48:51 +08:00
Alex Lam S.L
89198e0ad4 improve destructuring generation in ufuzz (#4428) 2020-12-20 13:38:56 +08:00
Alex Lam S.L
caea6aac81 handle destructuring catch in --reduce-test (#4427) 2020-12-20 11:22:45 +08:00
Alex Lam S.L
f5224ca1f5 fix corner case with destructuring catch (#4426)
fixes #4425
2020-12-20 10:31:32 +08:00
Alex Lam S.L
b7c49b72b3 support async function within object literal (#4424) 2020-12-20 08:19:04 +08:00
Alex Lam S.L
8ce3c7d70f fix corner case in evaluate & reduce_vars (#4423)
fixes #4422
2020-12-20 05:47:15 +08:00
Alex Lam S.L
87cf715213 fix corner case with destructuring catch (#4421)
fixes #4420
2020-12-20 05:47:01 +08:00
Alex Lam S.L
2c9c72e06c suppress false positives in ufuzz (#4419) 2020-12-20 02:31:09 +08:00
Alex Lam S.L
882968c68c fix corner case in inline (#4418)
fixes #4417
2020-12-20 01:24:29 +08:00
Alex Lam S.L
acc2d7d845 fix corner case in objects (#4416)
fixes #4415
2020-12-20 00:14:57 +08:00
Alex Lam S.L
9a5aede941 fix corner case in reduce_vars & unused (#4414)
fixes #4413
2020-12-19 12:47:46 +08:00
Alex Lam S.L
e6dd471f8f support destructuring of catch variable (#4412) 2020-12-19 12:28:38 +08:00
Alex Lam S.L
0f55bd92f1 fix corner case in arguments (#4411)
fixes #4410
2020-12-19 04:53:53 +08:00
Alex Lam S.L
7d9dad0289 fix corner case with parentheses (#4409)
fixes #4408
2020-12-19 01:01:49 +08:00
Alex Lam S.L
44e494f16f fix corner case in merge_vars (#4407)
fixes #4406
2020-12-19 00:52:37 +08:00
Alex Lam S.L
2415a72e75 fix corner case in unused (#4405)
fixes #4404
2020-12-18 23:45:41 +08:00
Alex Lam S.L
9c0718b162 enhance arrows (#4403) 2020-12-18 14:55:20 +08:00
Alex Lam S.L
d2c50ace99 fix corner case in merge_vars (#4402)
fixes #4401
2020-12-18 12:20:43 +08:00
Alex Lam S.L
1b646d3bc4 fix corner case in arguments (#4400)
fixes #4399
2020-12-18 10:12:01 +08:00
Alex Lam S.L
82d2aa4acf fix corner case in arguments (#4398)
fixes #4397
2020-12-18 09:42:07 +08:00
Alex Lam S.L
c1256c399a fix corner case in arguments (#4396)
fixes #4395
2020-12-18 08:41:13 +08:00
Alex Lam S.L
2c637fea8a fix corner case in evaluate & reduce_vars (#4394)
fixes #4393
2020-12-18 07:16:04 +08:00
Alex Lam S.L
4fa54b075c enhance reduce_vars (#4392) 2020-12-18 06:18:47 +08:00
Alex Lam S.L
ab82be82b2 fix corner case in collapse_vars (#4391)
fixes #4390
2020-12-18 03:10:16 +08:00
Alex Lam S.L
02fdcfde01 fix corner case in inline (#4389)
fixes #4388
2020-12-18 00:55:19 +08:00
Alex Lam S.L
a96f087ac3 support arrow function (#4385) 2020-12-17 18:23:41 +08:00
Alex Lam S.L
75e9fd8417 fix corner case in arguments (#4387)
fixes #4386
2020-12-17 13:51:34 +08:00
Alex Lam S.L
f68e267830 fix corner case in reduce_vars (#4384)
fixes #4383
2020-12-17 04:47:48 +08:00
Alex Lam S.L
8b10b93ee1 v3.12.2 2020-12-16 14:11:48 +08:00
Alex Lam S.L
549de028b6 fix corner case in objects (#4381)
fixes #4380
2020-12-15 21:23:55 +08:00
Alex Lam S.L
f579f1aa47 emulate global context in Node.js & web (#4379) 2020-12-14 02:05:07 +08:00
Alex Lam S.L
fcc40d0502 fix corner case in dead_code (#4378)
fixes #4377
2020-12-14 00:03:44 +08:00
Alex Lam S.L
b309527264 maintain compatibility options when testing (#4376) 2020-12-13 14:26:45 +08:00
Alex Lam S.L
5d19bb8d5d fix corner case in booleans (#4375)
fixes #4374
2020-12-13 05:01:38 +08:00
Alex Lam S.L
af97629912 fix corner case in dead_code (#4373)
fixes #4372
2020-12-13 02:24:18 +08:00
Alex Lam S.L
8c000033d3 clarify corner case in object literal (#4371)
closes #4366
2020-12-12 07:42:29 +08:00
Alex Lam S.L
fd0d28e465 fix corner case in spread (#4370) 2020-12-12 06:45:59 +08:00
Alex Lam S.L
2123f38394 fix asynchronous state tracking in ufuzz (#4369) 2020-12-12 05:19:56 +08:00
Alex Lam S.L
58dff9ada3 fix corner cases in unused & varify (#4368)
fixes #4365
2020-12-12 04:45:35 +08:00
Alex Lam S.L
4fdec765bc gate language features in ufuzz automatically (#4367) 2020-12-12 03:43:12 +08:00
Alex Lam S.L
1020d37256 fix corner case in spread (#4364)
fixes #4363
2020-12-12 02:19:11 +08:00
Alex Lam S.L
076739db07 fix corner case in unused (#4362)
fixes #4361
2020-12-12 00:57:05 +08:00
Alex Lam S.L
515e93d88a fix corner case in collapse_vars (#4360)
fixes #4359
2020-12-12 00:07:28 +08:00
Alex Lam S.L
57105b299e fix corner cases with spread syntax (#4358) 2020-12-11 06:59:21 +08:00
Alex Lam S.L
77e1bda426 improve fix for #4355 (#4357) 2020-12-11 00:48:41 +08:00
Alex Lam S.L
a59593cac8 fix corner case in loops & unused (#4356)
fixes #4355
2020-12-10 15:45:39 +08:00
Alex Lam S.L
046bbde9d4 fix corner case in keep_fargs & reduce_vars (#4354)
fixes #4353
2020-12-09 01:41:10 +08:00
Alex Lam S.L
fea9da9866 forbid AST_Await in computed function arguments (#4352)
fixes #4351
2020-12-08 12:59:08 +08:00
Alex Lam S.L
4733159782 fix corner cases with await (#4350)
fixes #4349
2020-12-08 11:26:03 +08:00
Alex Lam S.L
5fba98608c fix corner case in reduce_vars (#4348)
fixes #4347
2020-12-08 08:52:14 +08:00
Alex Lam S.L
c587d7917d introduce spread (#4346)
fixes #4345
2020-12-08 06:51:20 +08:00
Alex Lam S.L
336336f53f fix corner case with parentheses around await (#4344) 2020-12-08 04:29:54 +08:00
Alex Lam S.L
4bde50ce85 fix corner case in side_effects (#4343)
fixes #4342
2020-12-07 17:25:04 +08:00
Alex Lam S.L
fbecedf94c fix corner case in evaluate (#4341)
fixes #4340
2020-12-07 16:05:11 +08:00
Alex Lam S.L
2f31f95095 improve ufuzz (#4339) 2020-12-07 16:04:51 +08:00
Alex Lam S.L
6b603e1a62 fix corner case in unused (#4338)
fixes #4337
2020-12-07 13:23:53 +08:00
Alex Lam S.L
499f8d89ff fix corner case in inline (#4336)
fixes #4335
2020-12-07 11:30:37 +08:00
Alex Lam S.L
9eb65f3af3 extend trailing comma support (#4334) 2020-12-07 10:07:34 +08:00
Alex Lam S.L
2cbbf5c375 support async function (#4333) 2020-12-07 05:22:40 +08:00
Alex Lam S.L
3c384cf9a8 fix corner case in collapse_vars (#4332)
fixes #4331
2020-12-06 18:30:50 +08:00
Alex Lam S.L
37f4f56752 fix corner case in properties (#4330)
fixes #4329
2020-12-06 13:59:04 +08:00
Alex Lam S.L
1e4985ed9e support spread syntax (#4328) 2020-12-06 05:19:31 +08:00
Alex Lam S.L
d2d56e301e v3.12.1 2020-12-01 01:46:27 +08:00
Alex Lam S.L
9d34f8428b fix corner case in side_effects (#4326)
fixes #4325
2020-11-29 10:05:48 +08:00
Alex Lam S.L
f045e2b460 fix corner case in merge_vars (#4324)
fixes #4323
2020-11-29 05:38:24 +08:00
Alex Lam S.L
8791f258e3 fix corner case in inline (#4322)
fixes #4321
2020-11-29 03:48:42 +08:00
Alex Lam S.L
af1cca25bf fix corner case in inline (#4320)
fixes #4319
2020-11-27 01:31:06 +08:00
Alex Lam S.L
9b3a363604 fix infinite recursion in ufuzz (#4318) 2020-11-25 09:33:42 +08:00
Alex Lam S.L
1e8fa1aa1d fix corner case in passes & reduce_vars (#4316)
fixes #4315
2020-11-23 07:05:20 +08:00
Alex Lam S.L
9f67866147 v3.12.0 2020-11-23 01:10:39 +08:00
Alex Lam S.L
645d5a348b workaround Safari quirks (#4314)
fixes #1753
2020-11-21 10:30:46 +08:00
Alex Lam S.L
cf120c7cea fix corner case in merge_vars & reduce_vars (#4313)
fixes #4312
2020-11-21 08:57:59 +08:00
Alex Lam S.L
8d30902ba9 fix corner case in mangle (#4311) 2020-11-21 08:05:40 +08:00
Alex Lam S.L
02459cddf9 gate galio workaround (#4310) 2020-11-21 03:37:33 +08:00
Alex Lam S.L
1b579779be fix corner case in collapse_vars (#4309)
fixes #4308
2020-11-20 06:23:37 +08:00
Alex Lam S.L
b18b70f63b fix corner case in hoist_props (#4307) 2020-11-20 00:02:25 +08:00
Alex Lam S.L
641406d491 fix corner cases in reduce_vars & unused (#4306) 2020-11-19 11:25:36 +08:00
Alex Lam S.L
134ef0b1eb fix corner case in dead_code (#4304) 2020-11-19 08:34:55 +08:00
Alex Lam S.L
db87dcf13e enhance varify (#4303) 2020-11-19 07:58:33 +08:00
Alex Lam S.L
aecbabc587 fix corner case in merge_vars (#4302)
fixes #4301
2020-11-19 05:44:47 +08:00
Alex Lam S.L
fd6544b340 fix corner case reduce_vars (#4300)
fixes #4297
2020-11-19 01:11:28 +08:00
Alex Lam S.L
f6a83f7944 fix corner case in merge_vars (#4299)
fixes #4298
2020-11-18 23:43:55 +08:00
Alex Lam S.L
35283e5dd1 enhance arguments (#4296) 2020-11-18 11:39:32 +08:00
Alex Lam S.L
7a51c17ff0 fix corner case in merge_vars (#4295)
fixes #4294
2020-11-18 09:32:53 +08:00
Alex Lam S.L
aff842f2f9 fix corner case in arguments (#4293)
fixes #4291
2020-11-18 08:54:58 +08:00
Alex Lam S.L
0bedd031da fix corner cases in collapse_vars, unused & varify (#4292)
fixes #4290
2020-11-18 08:22:54 +08:00
Alex Lam S.L
caa92aea5d fix corner case in merge_vars (#4289)
fixes #4288
2020-11-18 04:03:20 +08:00
Alex Lam S.L
383163afa6 fix corner case in collapse_vars (#4287)
fixes #4286
2020-11-17 18:03:31 +08:00
Alex Lam S.L
8a83c8dd46 fix corner cases in collapse_vars & dead_code (#4285)
fixes #4284
2020-11-17 16:23:50 +08:00
Alex Lam S.L
2a612fd472 fix corner case in reduce_vars (#4283)
fixes #4282
2020-11-17 14:43:04 +08:00
Alex Lam S.L
b9798a01a8 fix corner case in reduce_vars (#4281)
fixes #4280
2020-11-17 12:59:44 +08:00
Alex Lam S.L
6dbacb5e3f enhance varify (#4279) 2020-11-17 12:35:00 +08:00
Alex Lam S.L
e5f80afc53 support destructured literals (#4278) 2020-11-17 08:01:24 +08:00
Alex Lam S.L
42e34c870a fix corner case in unused (#4277)
fixes #4276
2020-11-17 02:06:00 +08:00
Alex Lam S.L
e390e7e124 v3.11.6 2020-11-14 22:21:19 +08:00
Alex Lam S.L
6fd5b5b371 fix corner case in loops (#4275)
fixes #4274
2020-11-14 02:08:05 +08:00
Alex Lam S.L
fba27bfb71 fix corner case in evaluate (#4272)
fixes #4271
2020-11-11 00:06:13 +08:00
Alex Lam S.L
41310e6404 fix corner case in objects (#4270)
fixes #4269
2020-11-09 10:47:02 +08:00
Alex Lam S.L
91fc1c82b5 support computed property name in object literal (#4268) 2020-11-08 23:38:32 +08:00
Alex Lam S.L
810cd40356 fix corner case in inline (#4266)
fixes #4265
2020-11-08 18:50:08 +08:00
Alex Lam S.L
1cbd07e789 support shorthand method name in object literal (#4264) 2020-11-08 13:17:53 +08:00
Alex Lam S.L
b82de04775 support shorthand property name in object literal (#4263) 2020-11-08 10:44:44 +08:00
Alex Lam S.L
4bbeb09f7c fix corner case in reduce_vars (#4262)
fixes #4261
2020-11-07 10:00:04 +08:00
Alex Lam S.L
c2f6fd5fde fix corner case in functions (#4260)
fixes #4259
2020-11-06 03:55:25 +08:00
Alex Lam S.L
af4ea3ff69 v3.11.5 2020-11-03 08:59:02 +08:00
Alex Lam S.L
e7643248a3 fix corner case in merge_vars (#4258)
fixes #4257
2020-11-02 01:01:00 +08:00
Alex Lam S.L
68091dbf69 fix corner case in merge_vars (#4256)
fixes #4255
2020-11-01 14:34:07 +08:00
Alex Lam S.L
cbf7269296 fix corner case in merge_vars (#4254)
fixes #4253
2020-11-01 10:37:21 +08:00
Alex Lam S.L
d8563caba7 improve resilience against spurious time-outs (#4252) 2020-10-30 11:06:48 +08:00
Alex Lam S.L
2e0ad40fe6 fix corner case in ie8 (#4251)
fixes #4250
2020-10-30 11:06:31 +08:00
Alex Lam S.L
5d12abc41b fix corner cases in collapse_vars (#4249)
fixes #4248
2020-10-30 10:04:23 +08:00
Alex Lam S.L
79e5c3f564 improve warnings (#4247)
closes #4244
2020-10-27 17:39:33 +08:00
Alex Lam S.L
607f87c5cd fix corner case in booleans (#4246)
fixes #4245
2020-10-26 18:53:58 +08:00
Alex Lam S.L
b2775746a7 v3.11.4 2020-10-25 23:40:42 +00:00
Alex Lam S.L
e478da24c7 fix corner case in collapse_vars (#4243)
fixes #4242
2020-10-24 22:44:20 +08:00
Alex Lam S.L
c5df8355ba fix corner case in loops & unused (#4241)
fixes #4240
2020-10-24 13:33:48 +08:00
Alex Lam S.L
ff38d2471f improve resilience against npm failures (#4239) 2020-10-24 11:22:13 +08:00
Alex Lam S.L
8e86d05c32 fix corner case in merge_vars (#4238)
fixes #4237
2020-10-24 10:19:43 +08:00
Alex Lam S.L
9e40abeded fix corner case in unused (#4236)
fixes #4235
2020-10-22 22:19:47 +08:00
Alex Lam S.L
23ca7d675f fix corner case in functions (#4234)
fixes #4233
2020-10-22 10:13:11 +08:00
Alex Lam S.L
fd8c0212b8 fix corner case in ie8 (#4232)
fixes #4231
2020-10-20 14:02:39 +08:00
Alex Lam S.L
256950c2c0 fix corner case in ie8 (#4230)
fixes #4229
2020-10-20 06:13:23 +08:00
Alex Lam S.L
8ecaa40c6e extend support for Unicode (#4228) 2020-10-19 09:34:17 +08:00
Alex Lam S.L
96bf7fceab support let (#4227) 2020-10-19 08:32:39 +08:00
Alex Lam S.L
6c7226c10e v3.11.3 2020-10-19 07:25:47 +08:00
Alex Lam S.L
dc575919e2 fix corner case in side_effects (#4226)
fixes #4225
2020-10-18 22:13:10 +08:00
Alex Lam S.L
4298201938 flush stdout from ufuzz jobs properly (#4224) 2020-10-16 21:56:54 +08:00
Alex Lam S.L
4f833937fe fix corner case in inline (#4223)
fixes #4222
2020-10-15 21:52:40 +08:00
Alex Lam S.L
3d71e97dd1 fix corner cases in braces & sequences (#4221)
fixes #4220
2020-10-14 23:39:35 +08:00
Alex Lam S.L
7f35d9cee0 fix corner case in reduce_vars (#4219)
fixes #4218
2020-10-14 07:58:04 +08:00
Alex Lam S.L
9f8106e1d8 fix corner case in collapse_vars (#4217)
fixes #4216
2020-10-14 07:18:26 +08:00
Alex Lam S.L
b7b8435721 fix corner case in evaluate (#4215)
fixes #4214
2020-10-14 02:49:45 +08:00
Alex Lam S.L
c0c04c33bb fix corner cases in dead_code & reduce_vars (#4213)
fixes #4212
2020-10-14 00:09:17 +08:00
Alex Lam S.L
0e234a25c5 fix corner case in reduce_vars (#4211)
fixes #4210
2020-10-13 15:52:03 +08:00
Alex Lam S.L
3096f6fdad restore inline functionality disabled by #4204 (#4209) 2020-10-13 09:33:49 +08:00
Alex Lam S.L
176c09c6a5 fix corner case in reduce_vars & unused (#4208)
fixes #4207
2020-10-13 07:32:17 +08:00
Alex Lam S.L
9272f662c0 fix corner case in collapse_vars (#4206)
fixes #4205
2020-10-13 01:30:21 +08:00
Alex Lam S.L
4d33cb2f94 fix corner case in inilne (#4204)
fixes #4202
2020-10-12 23:10:32 +08:00
Alex Lam S.L
00d0eda85b fix corner case in arguments (#4201)
fixes #4200
2020-10-12 19:03:21 +08:00
Alex Lam S.L
1cdf810f0b fix corner case in reduce_vars (#4203)
fixes #4198
2020-10-12 19:02:44 +08:00
Alex Lam S.L
b512726cf3 fix corner case in collapse_vars (#4199)
fixes #4197
2020-10-12 14:13:17 +08:00
Alex Lam S.L
9b7a13c8c7 fix corner case in ie8 & mangle (#4196)
fixes #4195
2020-10-12 12:43:26 +08:00
Alex Lam S.L
74ff6ce261 fix corner case in dead_code (#4194)
fixes #4193
2020-10-12 11:09:26 +08:00
Alex Lam S.L
b1b8898e7c fix corner case in functions (#4192)
fixes #4191
2020-10-12 09:26:56 +08:00
Alex Lam S.L
55451e7b78 support const (#4190) 2020-10-12 01:18:57 +08:00
Alex Lam S.L
ffcce28ce1 v3.11.2 2020-10-11 21:19:25 +08:00
Alex Lam S.L
9c0feb69e5 fix corner case in reduce_vars (#4189)
fixes #4188
2020-10-07 22:01:39 +08:00
Alex Lam S.L
bc6e105174 fix corner case in ie8 (#4187)
fixes #4186
2020-10-06 09:20:41 +08:00
Alex Lam S.L
b91a2459c0 fix corner case in unused (#4185)
fixes #4184
2020-10-05 18:59:03 +08:00
Alex Lam S.L
b7a57fc69d fix corner case in loops (#4183)
fixes #4182
2020-10-05 17:28:46 +08:00
Alex Lam S.L
2dbe40b01b enhance conditionals (#4181) 2020-10-05 15:55:37 +08:00
Alex Lam S.L
813ac3ba96 enhance loops (#4180) 2020-10-05 08:26:59 +08:00
Alex Lam S.L
220dc95c0d clean up scope-related variables (#4179) 2020-10-05 06:56:52 +08:00
Alex Lam S.L
8f0521d51d retrofit try-catch-finally as block-scoped (#4178)
- support optional catch binding
2020-10-05 05:30:14 +08:00
Alex Lam S.L
f9946767c9 retrofit AST_BlockStatement as block-scoped (#4177) 2020-10-05 01:58:50 +08:00
Alex Lam S.L
58ac5b9bd5 extend support for numeral literals (#4176) 2020-10-05 00:05:03 +08:00
Alex Lam S.L
66140b459e enhance side_effects (#4175) 2020-10-04 23:43:49 +08:00
Alex Lam S.L
1786c69070 v3.11.1 2020-10-04 22:12:07 +08:00
Alex Lam S.L
95ef4d5377 fix corner case in mangle (#4174) 2020-10-04 08:24:41 +08:00
Alex Lam S.L
04017215cc support JSON dump beyond AST_Toplevel (#4173) 2020-10-03 22:53:06 +08:00
Alex Lam S.L
142bd1bd1a workaround quirks on latter specs (#4172)
closes #4171
2020-10-03 18:27:17 +08:00
Alex Lam S.L
8cb509d50e fix corner case in merge_vars (#4170)
fixes #4168
2020-10-03 07:03:39 +08:00
Alex Lam S.L
baf4903aa7 fix corner cases of catch variable inlining (#4169) 2020-10-03 07:02:28 +08:00
Alex Lam S.L
35465d590e report immediate ufuzz failure from Pull Request (#4166) 2020-10-02 23:43:38 +08:00
Alex Lam S.L
ccd91b9952 retrofit catch as block-scoped (#4165) 2020-10-02 23:29:58 +08:00
Alex Lam S.L
47a5e6e17a enhance if_return (#4164) 2020-10-02 16:10:25 +08:00
Alex Lam S.L
090ee895e1 enhance inline (#4163) 2020-09-30 21:03:28 +08:00
Alex Lam S.L
1cd1a1e5ee improve resilience against GitHub API (#4161) 2020-09-30 01:13:29 +08:00
Alex Lam S.L
1d835ac17d fix corner case in inline (#4160)
fixes #4159
2020-09-29 07:01:38 +08:00
Alex Lam S.L
9e07ac4102 fix corner case in merge_vars (#4158)
fixes #4157
2020-09-28 14:09:55 +08:00
Alex Lam S.L
92d1391e5e v3.11.0 2020-09-27 20:36:27 +08:00
Alex Lam S.L
b4ff6d0f2d fix corner cases in functions & merge_vars (#4156)
fixes #4155
2020-09-26 15:31:33 +08:00
Alex Lam S.L
9882a9f4af fix corner case in ufuzz scheduling (#4154) 2020-09-26 11:23:56 +08:00
Alex Lam S.L
40f36b9e01 improve ufuzz duty cycle heuristic (#4153) 2020-09-26 07:56:00 +08:00
Alex Lam S.L
6e105c5ca6 enhance merge_vars (#4152) 2020-09-25 22:00:20 +08:00
Alex Lam S.L
af35cd32f2 fix corner case in merge_vars (#4151) 2020-09-25 08:04:51 +08:00
Alex Lam S.L
7de8daa4b1 minor clean up (#4149) 2020-09-23 23:06:12 +08:00
Alex Lam S.L
305a4bdcee minor clean up (#4148) 2020-09-23 16:34:22 +08:00
Alex Lam S.L
3472cf1a90 fix corner case in unused (#4147)
fixes #4146
2020-09-22 20:08:45 +08:00
Alex Lam S.L
6d4c0fa6fa fix corner case in unused (#4145)
fixes #4144
2020-09-22 14:03:27 +08:00
Alex Lam S.L
3cca0d6249 fix corner case in evaluate (#4143)
fixes #4142
2020-09-22 12:11:25 +08:00
Alex Lam S.L
12ac49b970 Merge pull request #4141 from alexlamsl/unused
enhance `unused`
2020-09-22 02:21:43 +01:00
alexlamsl
8c670cae93 enhance unused 2020-09-22 07:48:55 +08:00
Alex Lam S.L
0e3da27727 fix corner case in merge_vars (#4140)
fixes #4139
2020-09-21 23:49:41 +01:00
Alex Lam S.L
13cdc167a2 fix corner case in evaluate (#4138)
fixes #4137
2020-09-22 06:49:32 +08:00
alexlamsl
51803cdcb2 fix corner case in merge_vars
fixes #4139
2020-09-22 05:03:06 +08:00
Alex Lam S.L
8fa470c17c fix corner case in merge_vars (#4136)
fixes #4135
2020-09-20 23:54:14 +08:00
Alex Lam S.L
90410f9fc3 fix corner case in unused (#4134)
fixes #4133
2020-09-20 23:21:59 +08:00
Alex Lam S.L
ef3831437d improve ufuzz duty cycle heuristic (#4132) 2020-09-20 08:29:35 +08:00
Alex Lam S.L
171c544705 fix corner case in merge_vars (#4131)
fixes #4130
2020-09-20 05:36:16 +08:00
Alex Lam S.L
3c609e2f4a enhance unused (#4129) 2020-09-20 01:45:52 +08:00
Alex Lam S.L
f0ae03ed39 report immediate ufuzz failure from Pull Request (#4128) 2020-09-19 20:31:37 +08:00
Alex Lam S.L
31c6b45036 fix corner case in merge_vars (#4127)
fixes #4126
2020-09-19 19:56:21 +08:00
Alex Lam S.L
3ac533e644 enhance merge_vars (#4125) 2020-09-19 11:16:23 +08:00
Alex Lam S.L
38a46c86d7 enhance side_effects (#4124)
- add documentation for `merge_vars`
2020-09-18 21:35:29 +08:00
Alex Lam S.L
0f0759ec15 remove redundant transform (#4123) 2020-09-18 07:04:46 +08:00
Alex Lam S.L
7f501f9fed add tests (#4122) 2020-09-18 00:26:31 +08:00
Alex Lam S.L
72844eb5a4 improve fix for #4119 (#4121) 2020-09-17 23:08:36 +08:00
Alex Lam S.L
09d93cc6c8 fix corner case in evaluate (#4120)
fixes #4119
2020-09-17 21:20:31 +08:00
Alex Lam S.L
dd1374aa8a minor clean up (#4118) 2020-09-17 07:10:45 +08:00
Alex Lam S.L
fdf2e8c5b0 enhance collapse_vars (#4117) 2020-09-17 06:35:22 +08:00
Alex Lam S.L
a9d934ab4e improve handling of switch statements (#4114) 2020-09-17 03:12:08 +08:00
Alex Lam S.L
2a053710bd fix corner case in merge_vars (#4116)
fixes #4115
2020-09-17 03:11:57 +08:00
Alex Lam S.L
219aac6a84 fix corner case in merge_vars (#4113)
fixes #4112
2020-09-16 22:18:28 +08:00
Alex Lam S.L
2039185051 enhance conditionals (#4106) 2020-09-16 05:51:42 +08:00
Alex Lam S.L
ad27c14202 fix corner cases in merge_vars (#4108)
fixes #4107
fixes #4109
fixes #4110
fixes #4111
2020-09-16 04:43:01 +08:00
Alex Lam S.L
a62b086184 enhance merge_vars (#4105) 2020-09-15 22:59:10 +08:00
Alex Lam S.L
335456cf77 fix corner case in merge_vars (#4104)
fixes #4103
2020-09-15 19:47:12 +08:00
Alex Lam S.L
d64d0b0bec fix corner case in merge_vars (#4102)
fixes #4101
2020-09-15 19:18:12 +08:00
Alex Lam S.L
3ac575f2e8 introduce merge_vars (#4100) 2020-09-15 10:01:48 +08:00
Alex Lam S.L
d33a3a3253 enhance unused (#4098) 2020-09-13 01:05:43 +08:00
Alex Lam S.L
d7456a2dc2 enhance if_return (#4097) 2020-09-10 22:31:34 +08:00
Alex Lam S.L
d97672613d fix corner case in reduce_vars (#4095) 2020-09-08 22:12:27 +08:00
Alex Lam S.L
30761eede5 v3.10.4 2020-09-07 00:25:54 +08:00
Alex Lam S.L
fb30aeccaf relax ufuzz job timing constraint (#4094) 2020-09-05 19:29:50 +08:00
Alex Lam S.L
226aa1f76b enhance unsafe_math (#4093) 2020-09-04 10:14:39 +08:00
Alex Lam S.L
6e235602fb fix corner case in loops & unused (#4092)
fixes #4091
2020-09-04 01:51:26 +08:00
Alex Lam S.L
980fcbb56b enhance unused (#4090) 2020-09-03 17:41:33 +08:00
Alex Lam S.L
375ebe316d enhance join_vars (#4089) 2020-09-03 01:41:10 +08:00
Alex Lam S.L
2500930234 enhance reduce_vars (#4088) 2020-09-02 11:30:46 +08:00
Alex Lam S.L
2f0da2ff05 reduce AST_ForIn gracefully (#4087) 2020-09-02 08:51:43 +08:00
Alex Lam S.L
83a3cbf151 fix test case runtime accounting (#4086) 2020-09-02 03:23:08 +08:00
Alex Lam S.L
da8d154571 fix corner case in loops & unused (#4085)
fixes #4084
2020-09-02 03:20:58 +08:00
Alex Lam S.L
e33c727e8b v3.10.3 2020-08-30 13:09:12 +01:00
Alex Lam S.L
f886b3fb2b fix corner case in loops & unused (#4083)
fixes #4082
2020-08-29 02:42:17 +08:00
Alex Lam S.L
b1cc15e85b fix corner case in sequences (#4080)
fixes #4079
2020-08-26 20:41:11 +08:00
Alex Lam S.L
3aa765e429 fix corner case in evaluate (#4078)
fixes #4077
2020-08-26 19:45:38 +08:00
Alex Lam S.L
93d084a1d1 fix corner case in loops & unused (#4076)
fixes #4075
2020-08-26 17:32:20 +08:00
Alex Lam S.L
c7a3e09407 enhance loops & unused (#4074)
- extend `ufuzz` generation of for-in loops
2020-08-26 09:32:55 +08:00
Alex Lam S.L
09525c7530 fix corner case in sequences (#4073) 2020-08-26 01:26:49 +08:00
Alex Lam S.L
a7e15fe73c streamline parenthesis logic (#4072) 2020-08-25 19:45:37 +08:00
Alex Lam S.L
a31c27c7cf fix corner case in collapse_vars (#4071)
fixes #4070
2020-08-25 17:23:36 +08:00
Alex Lam S.L
1caf7c7bd2 minor clean up (#4069) 2020-08-25 10:10:56 +08:00
Alex Lam S.L
0eb0c9b388 fix corner case in evaluate (#4068)
fixes #4067
2020-08-24 14:57:26 +08:00
Alex Lam S.L
7dc61cdc89 tidy up various interfaces (#4066) 2020-08-24 04:39:38 +08:00
Alex Lam S.L
af1b2f30c9 v3.10.2 2020-08-23 23:09:12 +08:00
Alex Lam S.L
37b4fc7e31 update domprops (#4065) 2020-08-23 23:06:15 +08:00
Alex Lam S.L
da85d102e3 enhance mangle.properties (#4064) 2020-08-23 08:45:39 +08:00
Alex Lam S.L
35fe1092d3 simplify traversal logic (#4063) 2020-08-23 05:45:35 +08:00
Alex Lam S.L
f2d486e771 enhance comparisons (#4062) 2020-08-23 01:03:48 +08:00
Alex Lam S.L
fee677786e fix corner case in collapse_vars (#4061) 2020-08-21 10:35:34 +08:00
Alex Lam S.L
aa83ecdb3b fix corner case in switches (#4060)
fixes #4059
2020-08-21 08:05:10 +08:00
Alex Lam S.L
a153176469 enhance conditionals & switches (#4058) 2020-08-21 00:35:39 +08:00
Alex Lam S.L
1c6384b6a5 improve ufuzz duty cycle heuristic (#4057) 2020-08-19 23:29:01 +08:00
Alex Lam S.L
e8db526f51 avoid setters during console.log() in sandbox (#4055)
fixes #4054
2020-08-19 06:14:41 +08:00
Alex Lam S.L
fa13ed4391 reject multiple defaults in switch (#4053)
fixes #4050
2020-08-17 10:09:12 +08:00
Alex Lam S.L
23f0dca992 fix corner cases in collapse_vars & dead_code (#4052)
fixes #4051
2020-08-17 05:54:27 +08:00
Alex Lam S.L
45ab3b51d8 clarify toplevel & global variable aliasing (#4046) 2020-08-10 06:39:28 +08:00
Alex Lam S.L
49670d216b fix corner case in collapse_vars (#4048)
fixes #4047
2020-08-10 05:48:56 +08:00
Alex Lam S.L
e2237d8cd2 improve ufuzz duty cycle heuristic (#4045) 2020-08-09 03:10:19 +08:00
Alex Lam S.L
91f078fe35 workaround incorrect workflow status (#4044) 2020-08-08 05:16:54 +08:00
Alex Lam S.L
a546cb881d improve ufuzz duty cycle on GitHub Actions (#4043) 2020-08-07 18:42:36 +08:00
Alex Lam S.L
84d5dffd9f tweak GitHub Actions (#4042) 2020-08-07 02:15:51 +08:00
Alex Lam S.L
a8e286f7e1 fix corner case in collapse_vars (#4041)
fixes #4040
2020-08-06 20:30:28 +08:00
Alex Lam S.L
9b05494ebc fix corner cases in aliasing of global variables (#4039)
fixes #4038
2020-08-06 09:39:50 +01:00
Alex Lam S.L
30ef20a208 tweak GitHub Actions (#4037) 2020-08-05 22:09:02 +08:00
Alex Lam S.L
a4002ef467 fix corner case in evaluate (#4036)
fixes #4035
2020-08-04 20:05:10 +08:00
Alex Lam S.L
9d758a216b v3.10.1 2020-08-02 21:08:48 +08:00
Alex Lam S.L
af13f8dd2c improve diagnostics upon AST validation failure (#4033) 2020-07-31 22:50:16 +08:00
Alex Lam S.L
88423f2574 validate against multiple parents on AST_Node (#4032)
- fix related issues in `global_defs`, `ie8` & `reduce_vars`
2020-07-31 08:09:19 +08:00
Alex Lam S.L
ee632a5519 fix corner case in reduce_vars (#4031)
fixes #4030
2020-07-31 08:05:09 +08:00
Alex Lam S.L
dfe47bcc42 fix corner case in ie8 & reduce_vars (#4029)
fixes #4028
2020-07-29 03:11:02 +08:00
Alex Lam S.L
6d3dcaa59e fix corner case in unused (#4026)
fixes #4025
2020-07-26 09:27:54 +08:00
Alex Lam S.L
1bc0df1569 fix corner case in hoist_props (#4024)
fixes #4023
2020-07-26 09:27:34 +08:00
Alex Lam S.L
a98ba994bd reduce ufuzz test cases that fail to minify() (#4021) 2020-07-21 17:22:18 +08:00
Alex Lam S.L
cd671221c5 fix corner case in ie8 & reduce_vars (#4020)
fixes #4019
2020-07-21 17:22:18 +08:00
Alex Lam S.L
bce3919748 fix corner case in unused (#4018)
fixes #4017
2020-07-21 17:21:58 +08:00
Alex Lam S.L
61b66e83f1 fix corner case in ie8 (#4016)
fixes #4015
2020-07-21 02:32:20 +08:00
Alex Lam S.L
a5db8cd14c fix corner case in collapse_vars (#4013)
fixes #4012
2020-07-20 23:28:13 +08:00
Alex Lam S.L
2021c2fa3e fix corner case in false positive detection (#4011) 2020-07-20 21:57:22 +08:00
Alex Lam S.L
484d3fd8c7 fix corner case in side_effects (#4009)
fixes #4008
2020-07-01 11:33:48 +08:00
Alex Lam S.L
3bf8699f95 fix corner case in inline (#4007)
fixes #4006
2020-06-29 09:06:23 +08:00
80 changed files with 22221 additions and 3259 deletions

View File

@@ -1,5 +1,8 @@
name: CI
on: [ push, pull_request ]
on:
pull_request:
push:
branches: [ master ]
jobs:
test:
strategy:
@@ -19,7 +22,7 @@ jobs:
TYPE: ${{ matrix.script }}
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v1
- uses: actions/cache@v2
with:
path: tmp
key: tmp ${{ matrix.script }}

View File

@@ -2,7 +2,12 @@ name: Fuzzing
on:
pull_request:
schedule:
- cron: "*/8 * * * *"
- cron: "*/5 * * * *"
env:
BASE_URL: https://api.github.com/repos/${{ github.repository }}
CAUSE: ${{ github.event_name }}
RUN_NUM: ${{ github.run_number }}
TOKEN: ${{ github.token }}
jobs:
ufuzz:
strategy:
@@ -32,4 +37,8 @@ jobs:
npm config set update-notifier false
npm --version
while !(npm install); do echo "'npm install' failed - retrying..."; done
node test/ufuzz/job 3600000
if [[ $CAUSE == "schedule" ]]; then
node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM
else
node test/ufuzz/job 5000
fi

116
README.md
View File

@@ -4,10 +4,12 @@ UglifyJS 3
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
#### Note:
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage)
that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
- `uglify-js` only supports JavaScript (ECMAScript 5).
- To minify ECMAScript 2015 or above, transpile using tools like [Babel](https://babeljs.io/).
- `uglify-js` supports ECMAScript 5 and some newer language features.
- To minify ECMAScript 2015 or above, you may need to transpile using tools like
[Babel](https://babeljs.io/).
Install
-------
@@ -135,6 +137,10 @@ a double dash to prevent input files being used as option arguments:
--toplevel Compress and/or mangle variables in top level scope.
--verbose Print diagnostic messages.
--warn Print warning messages.
--webkit Support non-standard Safari/Webkit.
Equivalent to setting `webkit: true` in `minify()`
for `mangle` and `output` options.
By default UglifyJS will not try to be Safari-proof.
--wrap <name> Embed everything in a big function, making the
“exports” and “global” variables available. You
need to pass an argument to this option to
@@ -212,17 +218,16 @@ Example:
To enable the mangler you need to pass `--mangle` (`-m`). The following
(comma-separated) options are supported:
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or
`with` are used.
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
- `reserved` (default: `[]`) -- when mangling is enabled but you want to
prevent certain names from being mangled, you can declare those names with
`--mangle reserved` — pass a comma-separated list of names. For example:
When mangling is enabled but you want to prevent certain names from being
mangled, you can declare those names with `--mangle reserved` — pass a
comma-separated list of names. For example:
uglifyjs ... -m reserved=['$','require','exports']
uglifyjs ... -m reserved=['$','require','exports']
to prevent the `require`, `exports` and `$` names from being changed.
to prevent the `require`, `exports` and `$` names from being changed.
### CLI mangling property names (`--mangle-props`)
@@ -520,6 +525,9 @@ if (result.error) throw result.error;
- `warnings` (default `false`) — pass `true` to return compressor warnings
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
- `webkit` (default `false`) -- enable workarounds for Safari/WebKit bugs.
PhantomJS users should set this option to `true`.
## Minify options structure
```javascript
@@ -657,8 +665,8 @@ to be `false` and all symbol names will be omitted.
- `hoist_props` (default: `true`) -- hoist properties from constant object and
array literals into regular variables subject to a set of constraints. For example:
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
and the `compress` option `toplevel` enabled.
works best with `toplevel` and `mangle` enabled, alongside with `compress` option
`passes` set to `2` or higher.
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
by default because it seems to increase the size of the output in general)
@@ -689,6 +697,8 @@ to be `false` and all symbol names will be omitted.
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
when we can statically determine the condition.
- `merge_vars` (default: `true`) -- combine and reuse variables.
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the
code generator would insert.
@@ -743,6 +753,8 @@ to be `false` and all symbol names will be omitted.
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();`
- `spread` (default: `true`) -- flatten spread expressions.
- `strings` (default: `true`) -- compact string concatenations.
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
@@ -783,6 +795,9 @@ to be `false` and all symbol names will be omitted.
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`)
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
whenever safe to do so
## Mangle options
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
@@ -864,6 +879,8 @@ can pass additional arguments that control the code output:
}
```
- `galio` (default `false`) -- enable workarounds for ANT Galio bugs
- `indent_level` (default `4`)
- `indent_start` (default `0`) -- prefix all lines by that many spaces
@@ -902,8 +919,7 @@ can pass additional arguments that control the code output:
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
PhantomJS users should set this option to `true`.
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
- `width` (default `80`) -- only takes effect when beautification is on, this
specifies an (orientative) line width that the beautifier will try to
@@ -1134,7 +1150,7 @@ To enable fast minify mode with the API use:
UglifyJS.minify(code, { compress: false, mangle: true });
```
#### Source maps and debugging
### Source maps and debugging
Various `compress` transforms that simplify, rearrange, inline and remove code
are known to have an adverse effect on debugging with source maps. This is
@@ -1146,6 +1162,10 @@ disable the Uglify `compress` option and just use `mangle`.
To allow for better optimizations, the compiler makes various assumptions:
- The code does not rely on preserving its runtime performance characteristics.
Typically uglified code will run faster due to less instructions and easier
inlining, but may be slower on rare occasions for a specific platform, e.g.
see [`reduce_funcs`](#compress-options).
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
objects they have not been overridden.
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
@@ -1157,3 +1177,67 @@ To allow for better optimizations, the compiler makes various assumptions:
- Object properties can be added, removed and modified (not prevented with
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
`Object.preventExtensions()` or `Object.seal()`).
- Earlier versions of JavaScript will throw `SyntaxError` with the following:
```js
({
p: 42,
get p() {},
});
// SyntaxError: Object literal may not have data and accessor property with
// the same name
```
UglifyJS may modify the input which in turn may suppress those errors.
- Iteration order of keys over an object which contains spread syntax in later
versions of Chrome and Node.js may be altered.
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped
within `function(){ ... }`, thus forbids aliasing of declared global variables:
```js
A = "FAIL";
var B = "FAIL";
// can be `global`, `self`, `window` etc.
var top = function() {
return this;
}();
// "PASS"
top.A = "PASS";
console.log(A);
// "FAIL" after compress and/or mangle
top.B = "PASS";
console.log(B);
```
- Use of `arguments` alongside destructuring as function parameters, e.g.
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
of Chrome and Node.js - UglifyJS may modify the input which in turn may
suppress those errors.
- Earlier versions of Chrome and Node.js will throw `ReferenceError` with the
following:
```js
var a;
try {
throw 42;
} catch ({
[a]: b,
// ReferenceError: a is not defined
}) {
let a;
}
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of JavaScript will throw `SyntaxError` with the following:
```js
a => {
let a;
};
// SyntaxError: Identifier 'a' has already been declared
```
UglifyJS may modify the input which in turn may suppress those errors.
- Later versions of JavaScript will throw `SyntaxError` with the following:
```js
try {
// ...
} catch ({ message: a }) {
var a;
}
// SyntaxError: Identifier 'a' has already been declared
```
UglifyJS may modify the input which in turn may suppress those errors.

View File

@@ -111,6 +111,7 @@ function process_option(name, no_value) {
" --validate Perform validation during AST manipulations.",
" --verbose Print diagnostic messages.",
" --warn Print warning messages.",
" --webkit Support non-standard Safari/Webkit.",
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
].join("\n"));
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
case "timings":
case "toplevel":
case "validate":
case "webkit":
options[name] = true;
break;
case "keep-fnames":
@@ -276,7 +278,9 @@ function convert_ast(fn) {
function run() {
var content = options.sourceMap && options.sourceMap.content;
if (content && content != "inline") {
UglifyJS.AST_Node.info("Using input source map: " + content);
UglifyJS.AST_Node.info("Using input source map: {content}", {
content : content,
});
options.sourceMap.content = read_file(content, content);
}
try {
@@ -342,7 +346,18 @@ function run() {
}
fatal(ex);
} else if (output == "ast") {
if (!options.compress && !options.mangle) result.ast.figure_out_scope({});
if (!options.compress && !options.mangle) {
var toplevel = result.ast;
if (!(toplevel instanceof UglifyJS.AST_Toplevel)) {
if (!(toplevel instanceof UglifyJS.AST_Statement)) toplevel = new UglifyJS.AST_SimpleStatement({
body: toplevel,
});
toplevel = new UglifyJS.AST_Toplevel({
body: [ toplevel ],
});
}
toplevel.figure_out_scope({});
}
print(JSON.stringify(result.ast, function(key, value) {
if (value) switch (key) {
case "thedef":

View File

@@ -120,20 +120,34 @@ var AST_Node = DEFNODE("Node", "start end", {
ctor.prototype._validate.call(this);
} while (ctor = ctor.BASE);
},
validate_ast: function() {
var marker = {};
this.walk(new TreeWalker(function(node) {
if (node.validate_visited === marker) {
throw new Error(string_template("cannot reuse {type} from [{file}:{line},{col}]", {
type: "AST_" + node.TYPE,
file: node.start.file,
line: node.start.line,
col: node.start.col,
}));
}
node.validate_visited = marker;
}));
},
}, null);
(AST_Node.log_function = function(fn, verbose) {
var printed = Object.create(null);
if (fn) {
AST_Node.info = verbose ? function(text, props) {
log("INFO: " + string_template(text, props));
} : noop;
AST_Node.warn = function(text, props) {
log("WARN: " + string_template(text, props));
};
} else {
if (!fn) {
AST_Node.info = AST_Node.warn = noop;
return;
}
var printed = Object.create(null);
AST_Node.info = verbose ? function(text, props) {
log("INFO: " + string_template(text, props));
} : noop;
AST_Node.warn = function(text, props) {
log("WARN: " + string_template(text, props));
};
function log(msg) {
if (printed[msg]) return;
@@ -189,9 +203,15 @@ var AST_Directive = DEFNODE("Directive", "value quote", {
},
}, AST_Statement);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)"
}, AST_Statement);
function must_be_expression(node, prop) {
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
throw new Error(prop + " cannot be AST_Statement");
}
}
@@ -212,6 +232,34 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
},
}, AST_Statement);
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
functions: "[Object/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
},
clone: function(deep) {
var node = this._clone(deep);
if (this.enclosed) node.enclosed = this.enclosed.slice();
if (this.functions) node.functions = this.functions.clone();
if (this.variables) node.variables = this.variables.clone();
return node;
},
pinned: function() {
return this.resolve().pinned();
},
resolve: function() {
return this.parent_scope.resolve();
},
_validate: function() {
if (this.parent_scope == null) return;
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
},
}, AST_Statement);
function walk_body(node, visitor) {
node.body.forEach(function(node) {
node.walk(visitor);
@@ -232,19 +280,15 @@ var AST_Block = DEFNODE("Block", "body", {
_validate: function() {
this.body.forEach(function(node) {
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
if (is_function(node)) throw new Error("body cannot contain AST_Function");
});
},
}, AST_Statement);
}, AST_BlockScope);
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
$documentation: "A block statement",
}, AST_Block);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)"
}, AST_Statement);
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
$propdoc: {
@@ -252,9 +296,9 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
},
_validate: function() {
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
if (is_function(this.body)) throw new Error("body cannot be AST_Function");
},
}, AST_Statement);
}, AST_BlockScope);
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
$documentation: "Statement with a label",
@@ -274,10 +318,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
var label = node.label;
var def = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
if (node instanceof AST_LoopControl) {
if (!node.label || node.label.thedef !== def) return;
node.label.thedef = label;
label.references.push(node);
return true;
}
if (node instanceof AST_Scope) return true;
}));
}
return node;
@@ -343,7 +390,7 @@ var AST_For = DEFNODE("For", "init condition step", {
if (this.init != null) {
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
if (this.init instanceof AST_Statement
&& !(this.init instanceof AST_Definitions || this.init instanceof AST_Function)) {
&& !(this.init instanceof AST_Definitions || is_function(this.init))) {
throw new Error("init cannot be AST_Statement");
}
}
@@ -369,8 +416,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
_validate: function() {
if (this.init instanceof AST_Definitions) {
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
} else if (!(this.init instanceof AST_PropAccess || this.init instanceof AST_SymbolRef)) {
throw new Error("init must be assignable");
} else {
validate_destructured(this.init, function(node) {
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
throw new Error("init must be assignable: " + node.TYPE);
}
});
}
must_be_expression(this, "object");
},
@@ -395,32 +446,16 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
parent_scope: "[AST_Scope?/S] link to the parent scope",
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
},
clone: function(deep) {
var node = this._clone(deep);
if (this.variables) node.variables = this.variables.clone();
if (this.functions) node.functions = this.functions.clone();
if (this.enclosed) node.enclosed = this.enclosed.slice();
return node;
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
},
pinned: function() {
return this.uses_eval || this.uses_with;
},
_validate: function() {
if (this.parent_scope != null) {
if (!(this.parent_scope instanceof AST_Scope)) throw new Error("parent_scope must be AST_Scope");
}
},
resolve: return_this,
}, AST_Block);
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
@@ -467,12 +502,23 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
}
}, AST_Scope);
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
$documentation: "Base class for functions",
$propdoc: {
name: "[AST_SymbolDeclaration?] the name of this function",
argnames: "[AST_SymbolFunarg*] array of function arguments",
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
},
each_argname: function(visit) {
var tw = new TreeWalker(function(node) {
if (node instanceof AST_DestructuredKeyVal) {
node.value.walk(tw);
return true;
}
if (node instanceof AST_SymbolFunarg) visit(node);
});
this.argnames.forEach(function(argname) {
argname.walk(tw);
});
},
walk: function(visitor) {
var node = this;
@@ -486,20 +532,61 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
},
_validate: function() {
this.argnames.forEach(function(node) {
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
validate_destructured(node, function(node) {
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
});
});
},
}, AST_Scope);
var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null.",
$documentation: "A getter/setter function",
_validate: function() {
if (this.name != null) throw new Error("name must be null");
},
}, AST_Lambda);
var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression",
function is_function(node) {
return node instanceof AST_Arrow || node instanceof AST_AsyncFunction || node instanceof AST_Function;
}
var AST_Arrow = DEFNODE("Arrow", "inlined value", {
$documentation: "An arrow function expression",
$propdoc: {
value: "[AST_Node?] simple return expression, or null if using function body.",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.argnames.forEach(function(argname) {
argname.walk(visitor);
});
if (node.value) {
node.value.walk(visitor);
} else {
walk_body(node, visitor);
}
});
},
_validate: function() {
if (this.name != null) throw new Error("name must be null");
if (this.uses_arguments) throw new Error("uses_arguments must be false");
if (this.value != null) {
must_be_expression(this, "value");
if (this.body.length) throw new Error("body must be empty if value exists");
}
},
}, AST_Lambda);
function is_async(node) {
return node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
}
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
$documentation: "An asynchronous function expression",
$propdoc: {
name: "[AST_SymbolLambda?] the name of this function",
},
_validate: function() {
if (this.name != null) {
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
@@ -507,8 +594,37 @@ var AST_Function = DEFNODE("Function", "inlined", {
},
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", "inlined", {
var AST_Function = DEFNODE("Function", "inlined name", {
$documentation: "A function expression",
$propdoc: {
name: "[AST_SymbolLambda?] the name of this function",
},
_validate: function() {
if (this.name != null) {
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
}
},
}, AST_Lambda);
function is_defun(node) {
return node instanceof AST_AsyncDefun || node instanceof AST_Defun;
}
var AST_AsyncDefun = DEFNODE("AsyncDefun", "inlined name", {
$documentation: "An asynchronous function definition",
$propdoc: {
name: "[AST_SymbolDefun] the name of this function",
},
_validate: function() {
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
},
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", "inlined name", {
$documentation: "A function definition",
$propdoc: {
name: "[AST_SymbolDefun] the name of this function",
},
_validate: function() {
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
},
@@ -593,7 +709,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
must_be_expression(this, "condition");
if (this.alternative != null) {
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
if (this.alternative instanceof AST_Function) throw new error("alternative cannot be AST_Function");
if (is_function(this.alternative)) throw new error("alternative cannot be AST_Function");
}
},
}, AST_StatementWithBody);
@@ -614,6 +730,9 @@ var AST_Switch = DEFNODE("Switch", "expression", {
},
_validate: function() {
must_be_expression(this, "expression");
this.body.forEach(function(node) {
if (!(node instanceof AST_SwitchBranch)) throw new Error("body must be AST_SwitchBranch[]");
});
},
}, AST_Block);
@@ -671,17 +790,19 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
var AST_Catch = DEFNODE("Catch", "argname", {
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
$propdoc: {
argname: "[AST_SymbolCatch] symbol for the exception"
argname: "[(AST_Destructured|AST_SymbolCatch)?] symbol for the exception, or null if not present",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.argname.walk(visitor);
if (node.argname) node.argname.walk(visitor);
walk_body(node, visitor);
});
},
_validate: function() {
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
if (this.argname != null) validate_destructured(this.argname, function(node) {
if (!(node instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
});
},
}, AST_Block);
@@ -703,14 +824,47 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
defn.walk(visitor);
});
});
}
},
_validate: function() {
if (this.definitions.length < 1) throw new Error("must have at least one definition");
},
}, AST_Statement);
var AST_Const = DEFNODE("Const", null, {
$documentation: "A `const` statement",
_validate: function() {
this.definitions.forEach(function(node) {
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
var AST_Let = DEFNODE("Let", null, {
$documentation: "A `let` statement",
_validate: function() {
this.definitions.forEach(function(node) {
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
var AST_Var = DEFNODE("Var", null, {
$documentation: "A `var` statement",
_validate: function() {
this.definitions.forEach(function(node) {
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -718,7 +872,7 @@ var AST_Var = DEFNODE("Var", null, {
var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_SymbolVar] name of the variable",
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer"
},
walk: function(visitor) {
@@ -728,18 +882,16 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
if (node.value) node.value.walk(visitor);
});
},
_validate: function() {
if (!(this.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
if (this.value != null) must_be_expression(this, "value");
},
});
/* -----[ OTHER ]----- */
function must_be_expressions(node, prop) {
function must_be_expressions(node, prop, allow_spread, allow_hole) {
node[prop].forEach(function(node) {
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
if (node instanceof AST_Statement && !(node instanceof AST_Function)) {
if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
if (node instanceof AST_Statement && !is_function(node)) {
throw new Error(prop + " cannot contain AST_Statement");
}
});
@@ -762,7 +914,7 @@ var AST_Call = DEFNODE("Call", "expression args pure", {
},
_validate: function() {
must_be_expression(this, "expression");
must_be_expressions(this, "args");
must_be_expressions(this, "args", true);
},
});
@@ -839,6 +991,22 @@ var AST_Sub = DEFNODE("Sub", null, {
},
}, AST_PropAccess);
var AST_Spread = DEFNODE("Spread", "expression", {
$documentation: "Spread expression in array/object literals or function calls",
$propdoc: {
expression: "[AST_Node] expression to be expanded",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.expression.walk(visitor);
});
},
_validate: function() {
must_be_expression(this, "expression");
},
});
var AST_Unary = DEFNODE("Unary", "operator expression", {
$documentation: "Base class for unary expressions",
$propdoc: {
@@ -912,9 +1080,33 @@ var AST_Assign = DEFNODE("Assign", null, {
$documentation: "An assignment expression — `a = b + 5`",
_validate: function() {
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
if (this.left instanceof AST_Destructured) {
if (this.operator != "=") throw new Error("invalid destructuring operator: " + this.operator);
validate_destructured(this.left, function(node) {
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
throw new Error("left must be assignable: " + node.TYPE);
}
});
}
},
}, AST_Binary);
var AST_Await = DEFNODE("Await", "expression", {
$documentation: "An await expression",
$propdoc: {
expression: "[AST_Node] expression with Promise to resolve on",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.expression.walk(visitor);
});
},
_validate: function() {
must_be_expression(this, "expression");
},
});
/* -----[ LITERALS ]----- */
var AST_Array = DEFNODE("Array", "elements", {
@@ -931,14 +1123,65 @@ var AST_Array = DEFNODE("Array", "elements", {
});
},
_validate: function() {
must_be_expressions(this, "elements");
must_be_expressions(this, "elements", true, true);
},
});
var AST_Object = DEFNODE("Object", "properties", {
$documentation: "An object literal",
var AST_Destructured = DEFNODE("Destructured", null, {
$documentation: "Base class for destructured literal",
});
function validate_destructured(node, check) {
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
});
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
validate_destructured(prop.value, check);
});
check(node);
}
var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
$documentation: "A destructured array literal",
$propdoc: {
properties: "[AST_ObjectProperty*] array of properties"
elements: "[AST_Node*] array of elements",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.elements.forEach(function(element) {
element.walk(visitor);
});
});
},
}, AST_Destructured);
var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
$documentation: "A key: value destructured property",
$propdoc: {
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
value: "[AST_Node] property value",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
if (node.key instanceof AST_Node) node.key.walk(visitor);
node.value.walk(visitor);
});
},
_validate: function() {
if (typeof this.key != "string") {
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
must_be_expression(this, "key");
}
must_be_expression(this, "value");
},
});
var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
$documentation: "A destructured object literal",
$propdoc: {
properties: "[AST_DestructuredKeyVal*] array of properties",
},
walk: function(visitor) {
var node = this;
@@ -950,7 +1193,29 @@ var AST_Object = DEFNODE("Object", "properties", {
},
_validate: function() {
this.properties.forEach(function(node) {
if (!(node instanceof AST_ObjectProperty)) throw new Error("properties must be AST_ObjectProperty[]");
if (!(node instanceof AST_DestructuredKeyVal)) throw new Error("properties must be AST_DestructuredKeyVal[]");
});
},
}, AST_Destructured);
var AST_Object = DEFNODE("Object", "properties", {
$documentation: "An object literal",
$propdoc: {
properties: "[(AST_ObjectProperty|AST_Spread)*] array of properties"
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.properties.forEach(function(prop) {
prop.walk(visitor);
});
});
},
_validate: function() {
this.properties.forEach(function(node) {
if (!(node instanceof AST_ObjectProperty || node instanceof AST_Spread)) {
throw new Error("properties must contain AST_ObjectProperty and/or AST_Spread only");
}
});
},
});
@@ -958,24 +1223,28 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
if (node.key instanceof AST_Node) node.key.walk(visitor);
node.value.walk(visitor);
});
}
});
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
$documentation: "A key: value object property",
$propdoc: {
quote: "[string] the original quote character"
},
_validate: function() {
if (typeof this.key != "string") throw new Error("key must be string");
if (typeof this.key != "string") {
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
must_be_expression(this, "key");
}
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
},
});
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
$documentation: "A key: value object property",
_validate: function() {
must_be_expression(this, "value");
},
}, AST_ObjectProperty);
@@ -983,7 +1252,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
$documentation: "An object setter property",
_validate: function() {
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
},
}, AST_ObjectProperty);
@@ -991,31 +1259,34 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
$documentation: "An object getter property",
_validate: function() {
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
},
}, AST_ObjectProperty);
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
$documentation: "Base class for all symbols",
$propdoc: {
name: "[string] name of this symbol",
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
thedef: "[SymbolDef/S] the definition of this symbol"
},
$documentation: "Base class for all symbols",
_validate: function() {
if (typeof this.name != "string") throw new Error("name must be string");
},
});
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
$documentation: "The name of a property accessor (setter/getter function)"
}, AST_Symbol);
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
}, AST_Symbol);
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
$documentation: "Symbol defining a constant",
}, AST_SymbolDeclaration);
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
$documentation: "Symbol defining a lexical-scoped variable",
}, AST_SymbolDeclaration);
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable",
}, AST_SymbolDeclaration);
@@ -1047,7 +1318,7 @@ var AST_Label = DEFNODE("Label", "references", {
}
}, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg", {
$documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol);
@@ -1223,14 +1494,13 @@ TreeWalker.prototype = {
|| 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;
for (var call, fn = p; call = this.parent(++i); fn = call) {
if (call.TYPE == "Call") {
if (!(fn instanceof AST_Lambda) || fn.name) return false;
} else if (fn instanceof AST_Lambda) {
return false;
}
}
} else {
return false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,9 @@ function read_source_map(name, toplevel) {
return to_ascii(match[2]);
}
}
AST_Node.warn("inline source map not found: " + name);
AST_Node.warn("inline source map not found: {name}", {
name: name,
});
}
function parse_source_map(content) {
@@ -87,6 +89,7 @@ function minify(files, options) {
toplevel: false,
validate: false,
warnings: false,
webkit: false,
wrap: false,
}, true);
if (options.validate) AST_Node.enable_validation();
@@ -99,6 +102,7 @@ function minify(files, options) {
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("webkit", options, [ "mangle", "output" ]);
var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
@@ -109,6 +113,7 @@ function minify(files, options) {
properties: false,
reserved: [],
toplevel: false,
webkit: false,
}, true);
if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
@@ -178,13 +183,17 @@ function minify(files, options) {
toplevel = toplevel[action](option);
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
});
if (options.validate) toplevel.validate_ast();
if (timings) timings.rename = Date.now();
if (options.rename) {
toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle);
}
if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (options.compress) {
toplevel = new Compressor(options.compress).compress(toplevel);
if (options.validate) toplevel.validate_ast();
}
if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
@@ -193,9 +202,7 @@ function minify(files, options) {
toplevel.mangle_names(options.mangle);
}
if (timings) timings.properties = Date.now();
if (options.mangle && options.mangle.properties) {
toplevel = mangle_properties(toplevel, options.mangle.properties);
}
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties);
if (timings) timings.output = Date.now();
var result = {};
if (options.output.ast) {
@@ -256,6 +263,7 @@ function minify(files, options) {
} catch (ex) {
return { error: ex };
} finally {
AST_Node.log_function();
AST_Node.disable_validation();
}
}

View File

@@ -115,9 +115,6 @@
value : from_moz(M.value)
};
if (M.kind == "init") return new AST_ObjectKeyVal(args);
args.key = new AST_SymbolAccessor({
name: args.key
});
args.value = new AST_Accessor(args.value);
if (M.kind == "get") return new AST_ObjectGetter(args);
if (M.kind == "set") return new AST_ObjectSetter(args);
@@ -385,7 +382,7 @@
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
var key = {
type: "Literal",
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
value: M.key
};
var kind;
if (M instanceof AST_ObjectKeyVal) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,8 @@
"use strict";
function find_builtins(reserved) {
var builtins = function() {
var names = [];
// NaN will be included due to Number.NaN
[
"null",
@@ -67,19 +68,21 @@ function find_builtins(reserved) {
].forEach(function(ctor) {
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
Object.getOwnPropertyNames(new ctor()).map(add);
Object.getOwnPropertyNames(ctor.prototype).map(add);
}
});
return makePredicate(names);
function add(name) {
push_uniq(reserved, name);
names.push(name);
}
}
}();
function reserve_quoted_keys(ast, reserved) {
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key);
if (node instanceof AST_ObjectProperty) {
if (node.start && node.start.quote) add(node.key);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
@@ -91,17 +94,14 @@ function reserve_quoted_keys(ast, reserved) {
}
function addStrings(node, add) {
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) {
addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) {
add(node.value);
} else if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
}
return true;
}));
if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
} else if (node instanceof AST_Sequence) {
addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) {
add(node.value);
}
}
function mangle_properties(ast, options) {
@@ -110,21 +110,21 @@ function mangle_properties(ast, options) {
cache: null,
debug: false,
keep_quoted: false,
only_cache: false,
regex: null,
reserved: null,
}, true);
var reserved = options.reserved;
if (!Array.isArray(reserved)) reserved = [];
if (!options.builtins) find_builtins(reserved);
var reserved = Object.create(options.builtins ? null : builtins);
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) {
reserved[name] = true;
});
var cname = -1;
var cache;
if (options.cache) {
cache = options.cache.props;
cache.each(function(mangled_name) {
push_uniq(reserved, mangled_name);
cache.each(function(name) {
reserved[name] = true;
});
} else {
cache = new Dictionary();
@@ -139,62 +139,86 @@ function mangle_properties(ast, options) {
var debug_suffix;
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
var names_to_mangle = [];
var unmangleable = [];
var names_to_mangle = Object.create(null);
var unmangleable = Object.create(reserved);
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal) {
add(node.key);
} else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above
add(node.key.name);
if (node instanceof AST_Binary) {
if (node.operator == "in") addStrings(node.left, add);
} else if (node.TYPE == "Call") {
var exp = node.expression;
if (exp instanceof AST_Dot) switch (exp.property) {
case "defineProperty":
case "getOwnPropertyDescriptor":
if (node.args.length < 2) break;
exp = exp.expression;
if (!(exp instanceof AST_SymbolRef)) break;
if (exp.name != "Object") break;
if (!exp.definition().undeclared) break;
addStrings(node.args[1], add);
break;
case "hasOwnProperty":
if (node.args.length < 1) break;
addStrings(node.args[0], add);
break;
}
} else if (node instanceof AST_Dot) {
add(node.property);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") add(node.key);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
} else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
addStrings(node.args[1], add);
}
}));
// step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node) {
if (node instanceof AST_ObjectKeyVal) {
node.key = mangle(node.key);
} else if (node instanceof AST_ObjectProperty) {
// setter or getter
node.key.name = mangle(node.key.name);
// step 2: renaming properties
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_Binary) {
if (node.operator == "in") mangleStrings(node.left);
} else if (node.TYPE == "Call") {
var exp = node.expression;
if (exp instanceof AST_Dot) switch (exp.property) {
case "defineProperty":
case "getOwnPropertyDescriptor":
if (node.args.length < 2) break;
exp = exp.expression;
if (!(exp instanceof AST_SymbolRef)) break;
if (exp.name != "Object") break;
if (!exp.definition().undeclared) break;
mangleStrings(node.args[1]);
break;
case "hasOwnProperty":
if (node.args.length < 1) break;
mangleStrings(node.args[0]);
break;
}
} else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
} else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property);
} else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
node.args[1] = mangleStrings(node.args[1]);
} else if (node instanceof AST_ObjectProperty) {
if (typeof node.key == "string") node.key = mangle(node.key);
} else if (node instanceof AST_Sub) {
if (!options.keep_quoted) mangleStrings(node.property);
}
}));
// only function declarations after this line
function can_mangle(name) {
if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) return cache.has(name);
if (unmangleable[name]) return false;
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true;
}
function should_mangle(name) {
if (reserved[name]) return false;
if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false;
return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
return cache.has(name) || names_to_mangle[name];
}
function add(name) {
if (can_mangle(name)) push_uniq(names_to_mangle, name);
if (!should_mangle(name)) push_uniq(unmangleable, name);
if (can_mangle(name)) names_to_mangle[name] = true;
if (!should_mangle(name)) unmangleable[name] = true;
}
function mangle(name) {
@@ -218,17 +242,13 @@ function mangle_properties(ast, options) {
}
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]);
} else if (node instanceof AST_String) {
node.value = mangle(node.value);
} else if (node instanceof AST_Conditional) {
node.consequent = mangleStrings(node.consequent);
node.alternative = mangleStrings(node.alternative);
}
return node;
}));
if (node instanceof AST_Sequence) {
mangleStrings(node.expressions.tail_node());
} else if (node instanceof AST_String) {
node.value = mangle(node.value);
} else if (node instanceof AST_Conditional) {
mangleStrings(node.consequent);
mangleStrings(node.alternative);
}
}
}

View File

@@ -59,6 +59,37 @@ function SymbolDef(id, scope, orig, init) {
}
SymbolDef.prototype = {
forEach: function(fn) {
this.orig.forEach(fn);
this.references.forEach(fn);
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
if (this.global && cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name);
} else if (!this.mangled_name && !this.unmangleable(options)) {
var def = this.redefined();
if (def) {
this.mangled_name = def.mangled_name || def.name;
} else {
this.mangled_name = next_mangled_name(this, options);
}
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
}
},
redefined: function() {
var scope = this.defun;
if (!scope) return;
var name = this.name;
var def = scope.variables.get(name)
|| scope instanceof AST_Toplevel && scope.globals.get(name)
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
return def.name == name;
}, scope.enclosed);
if (def && def !== this) return def.redefined() || def;
},
unmangleable: function(options) {
return this.global && !options.toplevel
|| this.undeclared
@@ -67,27 +98,10 @@ SymbolDef.prototype = {
&& (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun);
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
if (this.global && cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name);
} else if (!this.mangled_name && !this.unmangleable(options)) {
var def;
if (def = this.redefined()) {
this.mangled_name = def.mangled_name || def.name;
} else {
this.mangled_name = next_mangled_name(this.scope, options, this);
}
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
}
},
redefined: function() {
return this.defun && this.defun.variables.get(this.name);
}
};
var unary_side_effects = makePredicate("delete ++ --");
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
options = defaults(options, {
cache: null,
@@ -96,30 +110,46 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// pass 1: setup scope chaining and handle definitions
var self = this;
var scope = self.parent_scope = null;
var defun = null;
var next_def_id = 0;
var scope = self.parent_scope = null;
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars(save_scope);
descend();
scope = save_scope;
if (is_defun(node)) {
node.name.walk(tw);
walk_scope(function() {
node.argnames.forEach(function(argname) {
argname.walk(tw);
});
walk_body(node, tw);
});
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
defun = scope = node;
if (node instanceof AST_SwitchBranch) {
node.init_vars(scope);
descend();
scope = save_scope;
defun = save_defun;
return true;
}
if (node instanceof AST_Try) {
walk_scope(function() {
walk_body(node, tw);
});
if (node.bcatch) node.bcatch.walk(tw);
if (node.bfinally) node.bfinally.walk(tw);
return true;
}
if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
return;
var s = scope;
do {
s = s.resolve();
if (s.uses_with) break;
s.uses_with = true;
} while (s = s.parent_scope);
walk_scope(descend);
return true;
}
if (node instanceof AST_BlockScope) {
walk_scope(descend);
return true;
}
if (node instanceof AST_Symbol) {
node.scope = scope;
@@ -128,60 +158,82 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
node.thedef = node;
node.references = [];
}
if (node instanceof AST_SymbolDefun) {
// This should be defined in the parent scope, as we encounter the
// AST_Defun node before getting to its AST_Symbol.
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun;
} else if (node instanceof AST_SymbolConst) {
scope.def_variable(node).defun = defun;
} else if (node instanceof AST_SymbolDefun) {
defun.def_function(node, tw.parent());
entangle(defun, scope);
} else if (node instanceof AST_SymbolFunarg) {
defun.def_variable(node);
entangle(defun, scope);
} else if (node instanceof AST_SymbolLambda) {
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
if (options.ie8) def.defun = defun.parent_scope.resolve();
} else if (node instanceof AST_SymbolLet) {
scope.def_variable(node);
} else if (node instanceof AST_SymbolVar) {
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
}
node.reference(options);
}
} else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun;
defun.def_variable(node, null);
entangle(defun, scope);
}
function walk_scope(descend) {
node.init_vars(scope);
var save_defun = defun;
var save_scope = scope;
if (node instanceof AST_Scope) defun = node;
scope = node;
descend();
scope = save_scope;
defun = save_defun;
}
function entangle(defun, scope) {
if (defun === scope) return;
node.mark_enclosed(options);
var def = scope.find_variable(node.name);
if (node.thedef === def) return;
node.thedef = def;
def.orig.push(node);
node.mark_enclosed(options);
}
});
self.next_def_id = 0;
self.make_def = function(orig, init) {
return new SymbolDef(++next_def_id, this, orig, init);
};
self.walk(tw);
// pass 2: find back references and eval
self.globals = new Dictionary();
var in_arg = [];
var tw = new TreeWalker(function(node) {
if (node instanceof AST_Catch) {
if (!(node.argname instanceof AST_Destructured)) return;
in_arg.push(node);
node.argname.walk(tw);
in_arg.pop();
walk_body(node, tw);
return true;
}
if (node instanceof AST_Lambda) {
in_arg.push(node);
node.argnames.forEach(function(argname) {
argname.walk(tw);
});
in_arg.pop();
if (node instanceof AST_Arrow && node.value) {
node.value.walk(tw);
} else {
walk_body(node, tw);
}
return true;
}
if (node instanceof AST_LoopControl) {
if (node.label) node.label.thedef.references.push(node);
return true;
}
if (node instanceof AST_SymbolRef) {
var name = node.name;
var sym = node.scope.find_variable(name);
if (!sym) {
sym = self.def_global(node);
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
sym.scope.uses_arguments = true;
}
if (name == "eval") {
var parent = tw.parent();
if (parent.TYPE == "Call" && parent.expression === node) {
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
s.uses_eval = true;
}
} else if (sym.undeclared) {
self.uses_eval = true;
}
}
node.thedef = sym;
node.reference(options);
return true;
}
// ensure mangling works if catch reuses a scope variable
// ensure mangling works if `catch` reuses a scope variable
if (node instanceof AST_SymbolCatch) {
var def = node.definition().redefined();
if (def) for (var s = node.scope; s; s = s.parent_scope) {
@@ -190,6 +242,61 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
return true;
}
// ensure compression works if `const` reuses a scope variable
if (node instanceof AST_SymbolConst) {
var redef = node.definition().redefined();
if (redef) redef.const_redefs = true;
return true;
}
if (node instanceof AST_SymbolRef) {
var name = node.name;
var sym = node.scope.find_variable(name);
for (var i = in_arg.length; i > 0 && sym;) {
i = in_arg.lastIndexOf(sym.scope, i - 1);
if (i < 0) break;
var decl = sym.orig[0];
if (decl instanceof AST_SymbolCatch
|| decl instanceof AST_SymbolFunarg
|| decl instanceof AST_SymbolLambda) {
node.in_arg = true;
break;
}
sym = sym.scope.parent_scope.find_variable(name);
}
if (!sym) {
sym = self.def_global(node);
} else if (name == "arguments"
&& sym.orig[0] instanceof AST_SymbolFunarg
&& !(sym.orig[1] instanceof AST_SymbolFunarg)
&& !(sym.scope instanceof AST_Arrow)) {
var parent = tw.parent();
if (parent instanceof AST_Assign && parent.left === node
|| parent instanceof AST_Unary && unary_side_effects[parent.operator]) {
sym.scope.uses_arguments = 3;
} else if (sym.scope.uses_arguments < 2
&& !(parent instanceof AST_PropAccess && parent.expression === node)) {
sym.scope.uses_arguments = 2;
} else if (!sym.scope.uses_arguments) {
sym.scope.uses_arguments = true;
}
}
if (name == "eval") {
var parent = tw.parent();
if (parent.TYPE == "Call" && parent.expression === node) {
var s = node.scope;
do {
s = s.resolve();
if (s.uses_eval) break;
s.uses_eval = true;
} while (s = s.parent_scope);
} else if (sym.undeclared) {
self.uses_eval = true;
}
}
node.thedef = sym;
node.reference(options);
return true;
}
});
self.walk(tw);
@@ -218,10 +325,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
function redefine(node, scope) {
var name = node.name;
var old_def = node.thedef;
if (!all(old_def.orig, function(sym) {
return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet);
})) return;
var new_def = scope.find_variable(name);
if (new_def) {
var redef;
while (redef = new_def.redefined()) new_def = redef;
var redef = new_def.redefined();
if (redef) new_def = redef;
} else {
new_def = self.globals.get(name);
}
@@ -230,7 +340,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
} else {
new_def = scope.def_variable(node);
}
old_def.orig.concat(old_def.references).forEach(function(node) {
old_def.defun = new_def.scope;
old_def.forEach(function(node) {
node.redef = true;
node.thedef = new_def;
node.reference(options);
});
@@ -239,12 +351,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
});
AST_Scope.DEFMETHOD("make_def", function(orig, init) {
var top = this;
while (top.parent_scope) top = top.parent_scope;
return new SymbolDef(++top.next_def_id, this, orig, init);
});
AST_Toplevel.DEFMETHOD("def_global", function(node) {
var globals = this.globals, name = node.name;
if (globals.has(name)) {
@@ -258,24 +364,38 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
this.parent_scope = parent_scope; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables
});
function init_block_vars(scope, parent) {
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
scope.parent_scope = parent; // the parent scope (null if this is the top level)
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
}
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
function init_scope_vars(scope, parent) {
init_block_vars(scope, parent);
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
}
AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) {
init_block_vars(this, parent_scope);
});
AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
init_scope_vars(this, parent_scope);
});
AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) {
init_scope_vars(this, parent_scope);
});
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
init_scope_vars(this, parent_scope);
this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({
name: "arguments",
start: this.start,
end: this.end
end: this.end,
}));
return this;
});
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
@@ -296,24 +416,23 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
this.mark_enclosed(options);
});
AST_Scope.DEFMETHOD("find_variable", function(name) {
if (name instanceof AST_Symbol) name = name.name;
AST_BlockScope.DEFMETHOD("find_variable", function(name) {
return this.variables.get(name)
|| (this.parent_scope && this.parent_scope.find_variable(name));
|| this.parent_scope && this.parent_scope.find_variable(name);
});
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
var def = this.def_variable(symbol, init);
if (!def.init || def.init instanceof AST_Defun) def.init = init;
if (!def.init || is_defun(def.init)) def.init = init;
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
if (def.init instanceof AST_Function) def.init = init;
if (is_function(def.init)) def.init = init;
} else {
def = this.make_def(symbol, init);
this.variables.set(symbol.name, def);
@@ -322,17 +441,12 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
return symbol.thedef = def;
});
AST_Lambda.DEFMETHOD("resolve", return_this);
AST_Scope.DEFMETHOD("resolve", function() {
return this.parent_scope.resolve();
});
AST_Toplevel.DEFMETHOD("resolve", return_this);
function names_in_use(scope, options) {
var names = scope.names_in_use;
if (!names) {
scope.names_in_use = names = Object.create(scope.mangled_names || null);
scope.cname = -1;
scope.cname_holes = [];
scope.names_in_use = names = Object.create(null);
var cache = options.cache && options.cache.props;
scope.enclosed.forEach(function(def) {
if (def.unmangleable(options)) names[def.name] = true;
@@ -344,12 +458,13 @@ function names_in_use(scope, options) {
return names;
}
function next_mangled_name(scope, options, def) {
function next_mangled_name(def, options) {
var scope = def.scope;
var in_use = names_in_use(scope, options);
var holes = scope.cname_holes;
var names = Object.create(null);
var scopes = [ scope ];
def.references.forEach(function(sym) {
def.forEach(function(sym) {
var scope = sym.scope;
do {
if (scopes.indexOf(scope) < 0) {
@@ -365,7 +480,7 @@ function next_mangled_name(scope, options, def) {
name = base54(holes[i]);
if (names[name]) continue;
holes.splice(i, 1);
scope.names_in_use[name] = true;
in_use[name] = true;
return name;
}
while (true) {
@@ -374,7 +489,7 @@ function next_mangled_name(scope, options, def) {
if (!names[name]) break;
holes.push(scope.cname);
}
scope.names_in_use[name] = true;
in_use[name] = true;
return name;
}
@@ -386,18 +501,10 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options) {
// labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function() {
return !this.definition().references.length && !this.scope.pinned();
});
AST_Symbol.DEFMETHOD("definition", function() {
return this.thedef;
});
AST_Symbol.DEFMETHOD("global", function() {
return this.definition().global;
});
function _default_mangler_options(options) {
options = defaults(options, {
eval : false,
@@ -405,6 +512,7 @@ function _default_mangler_options(options) {
keep_fnames : false,
reserved : [],
toplevel : false,
webkit : false,
});
if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
@@ -423,7 +531,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
var lname = -1;
if (options.cache && options.cache.props) {
var mangled_names = this.mangled_names = Object.create(null);
var mangled_names = names_in_use(this, options);
options.cache.props.each(function(mangled_name) {
mangled_names[mangled_name] = true;
});
@@ -438,7 +546,26 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
lname = save_nesting;
return true;
}
if (node instanceof AST_Scope) {
if (node instanceof AST_BlockScope) {
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
node.init.definitions.forEach(function(defn) {
defn.name.match_symbol(function(sym) {
if (!(sym instanceof AST_SymbolLet)) return;
var def = sym.definition();
var scope = sym.scope.parent_scope;
var redef = scope.def_variable(sym);
sym.thedef = def;
scope.to_mangle.push(redef);
def.redefined = function() {
return redef;
};
});
}, true);
}
node.to_mangle = [];
node.variables.each(function(def) {
if (!defer_redef(def)) node.to_mangle.push(def);
});
descend();
if (options.cache && node instanceof AST_Toplevel) {
node.globals.each(mangle);
@@ -448,9 +575,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
sym.scope = node;
sym.reference(options);
}
node.variables.each(function(def) {
if (!defer_redef(def)) mangle(def);
});
node.to_mangle.forEach(mangle);
return true;
}
if (node instanceof AST_Label) {
@@ -461,13 +586,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
node.mangled_name = name;
return true;
}
if (!options.ie8 && node instanceof AST_Catch) {
var def = node.argname.definition();
var redef = defer_redef(def, node.argname);
descend();
if (!redef) mangle(def);
return true;
}
});
this.walk(tw);
redefined.forEach(mangle);
@@ -477,12 +595,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
def.mangle(options);
}
function defer_redef(def, node) {
function defer_redef(def) {
var sym = def.orig[0];
var redef = def.redefined();
if (!redef) return false;
if (!redef) {
if (!(sym instanceof AST_SymbolConst)) return false;
var scope = def.scope.resolve();
if (def.scope === scope) return false;
redef = scope.def_variable(sym);
scope.to_mangle.push(redef);
}
redefined.push(def);
def.references.forEach(reference);
if (node) reference(node);
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
return true;
function reference(sym) {
@@ -495,12 +620,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
var cache = options.cache && options.cache.props;
var avoid = Object.create(null);
var avoid = Object.create(RESERVED_WORDS);
options.reserved.forEach(to_avoid);
this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
if (node instanceof AST_BlockScope) node.variables.each(add_def);
}));
return avoid;
@@ -524,15 +648,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var cname = 0;
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
if (node instanceof AST_BlockScope) node.variables.each(rename);
}));
function next_name() {
var name;
do {
name = base54(cname++);
} while (avoid[name] || RESERVED_WORDS[name]);
} while (avoid[name]);
return name;
}
@@ -543,7 +666,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var redef = def.redefined();
var name = redef ? redef.rename || redef.name : next_name();
def.rename = name;
def.orig.concat(def.references).forEach(function(sym) {
def.forEach(function(sym) {
if (sym.definition() === def) sym.name = name;
});
}
@@ -557,22 +680,24 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
options = _default_mangler_options(options);
base54.reset();
var fn = AST_Symbol.prototype.add_source_map;
try {
AST_Node.prototype.print = function(stream, force_parens) {
this._print(stream, force_parens);
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
base54.consider(this.name, -1);
} else if (options.properties) {
if (this instanceof AST_Dot) {
base54.consider(this.property, -1);
} else if (this instanceof AST_Sub) {
skip_string(this.property);
}
}
AST_Symbol.prototype.add_source_map = function() {
if (!this.unmangleable(options)) base54.consider(this.name, -1);
};
if (options.properties) {
AST_Dot.prototype.add_source_map = function() {
base54.consider(this.property, -1);
};
AST_Sub.prototype.add_source_map = function() {
skip_string(this.property);
};
}
base54.consider(this.print_to_string(), 1);
} finally {
AST_Node.prototype.print = AST_Node.prototype._print;
AST_Symbol.prototype.add_source_map = fn;
delete AST_Dot.prototype.add_source_map;
delete AST_Sub.prototype.add_source_map;
}
base54.sort();

View File

@@ -116,7 +116,7 @@ TreeTransformer.prototype = new TreeWalker;
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
});
DEF(AST_Catch, function(self, tw) {
self.argname = self.argname.transform(tw);
if (self.argname) self.argname = self.argname.transform(tw);
self.body = do_list(self.body, tw);
});
DEF(AST_Definitions, function(self, tw) {
@@ -131,6 +131,14 @@ TreeTransformer.prototype = new TreeWalker;
self.argnames = do_list(self.argnames, tw);
self.body = do_list(self.body, tw);
});
DEF(AST_Arrow, function(self, tw) {
self.argnames = do_list(self.argnames, tw);
if (self.value) {
self.value = self.value.transform(tw);
} else {
self.body = do_list(self.body, tw);
}
});
DEF(AST_Call, function(self, tw) {
self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw);
@@ -138,6 +146,9 @@ TreeTransformer.prototype = new TreeWalker;
DEF(AST_Sequence, function(self, tw) {
self.expressions = do_list(self.expressions, tw);
});
DEF(AST_Await, function(self, tw) {
self.expression = self.expression.transform(tw);
});
DEF(AST_Dot, function(self, tw) {
self.expression = self.expression.transform(tw);
});
@@ -145,6 +156,9 @@ TreeTransformer.prototype = new TreeWalker;
self.expression = self.expression.transform(tw);
self.property = self.property.transform(tw);
});
DEF(AST_Spread, function(self, tw) {
self.expression = self.expression.transform(tw);
});
DEF(AST_Unary, function(self, tw) {
self.expression = self.expression.transform(tw);
});
@@ -160,10 +174,21 @@ TreeTransformer.prototype = new TreeWalker;
DEF(AST_Array, function(self, tw) {
self.elements = do_list(self.elements, tw);
});
DEF(AST_DestructuredArray, function(self, tw) {
self.elements = do_list(self.elements, tw);
});
DEF(AST_DestructuredKeyVal, function(self, tw) {
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
self.value = self.value.transform(tw);
});
DEF(AST_DestructuredObject, function(self, tw) {
self.properties = do_list(self.properties, tw);
});
DEF(AST_Object, function(self, tw) {
self.properties = do_list(self.properties, tw);
});
DEF(AST_ObjectProperty, function(self, tw) {
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
self.value = self.value.transform(tw);
});
})(function(node, descend) {

View File

@@ -112,51 +112,29 @@ function return_this() { return this; }
function return_null() { return null; }
var List = (function() {
function List(a, f, backwards) {
var ret = [], top = [], i;
function doit() {
function List(a, f) {
var ret = [];
for (var i = 0; i < a.length; i++) {
var val = f(a[i], i);
var is_last = val instanceof Last;
if (is_last) val = val.v;
if (val instanceof AtTop) {
val = val.v;
if (val instanceof Splice) {
top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
} else {
top.push(val);
}
} else if (val !== skip) {
if (val instanceof Splice) {
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
} else {
ret.push(val);
}
}
return is_last;
}
if (Array.isArray(a)) {
if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break;
ret.reverse();
top.reverse();
if (val === skip) continue;
if (val instanceof Splice) {
ret.push.apply(ret, val.v);
} else {
for (i = 0; i < a.length; ++i) if (doit()) break;
ret.push(val);
}
} else {
for (i in a) if (HOP(a, i)) if (doit()) break;
}
return top.concat(ret);
return ret;
}
List.is_op = function(val) {
return val === skip || val instanceof AtTop || val instanceof Last || val instanceof Splice;
return val === skip || val instanceof Splice;
};
List.splice = function(val) {
return new Splice(val);
};
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; }
function Splice(val) {
this.v = val;
}
return List;
})();
@@ -165,8 +143,9 @@ function push_uniq(array, el) {
}
function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p) {
return props && props[p];
return text.replace(/\{([^}]+)\}/g, function(str, p) {
var value = props[p];
return value instanceof AST_Node ? value.print_to_string() : value;
});
}
@@ -259,13 +238,15 @@ function HOP(obj, prop) {
// return true if the node at the top of the stack (that means the
// innermost node in the current output) is lexically the first in
// a statement.
function first_in_statement(stack) {
function first_in_statement(stack, arrow) {
var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i++); node = p) {
if (p.TYPE == "Call") {
if (p.expression === node) continue;
if (p instanceof AST_Arrow) {
return arrow && p.value === node;
} else if (p instanceof AST_Binary) {
if (p.left === node) continue;
} else if (p.TYPE == "Call") {
if (p.expression === node) continue;
} else if (p instanceof AST_Conditional) {
if (p.condition === node) continue;
} else if (p instanceof AST_PropAccess) {

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

View File

@@ -63,7 +63,6 @@ function make_code(ast, options) {
function parse_test(file) {
var script = fs.readFileSync(file, "utf8");
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
try {
var ast = U.parse(script, {
filename: file
@@ -269,6 +268,7 @@ function test_case(test) {
quote_style: 3,
});
try {
input.validate_ast();
U.parse(input_code);
} catch (ex) {
log([
@@ -311,12 +311,11 @@ function test_case(test) {
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (test.mangle.properties) {
output = U.mangle_properties(output, test.mangle.properties);
}
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
}
output = make_code(output, output_options);
if (expect != output) {
var output_code = make_code(output, output_options);
U.AST_Node.log_function();
if (expect != output_code) {
log([
"!!! failed",
"---INPUT---",
@@ -329,14 +328,15 @@ function test_case(test) {
"",
].join("\n"), {
input: input_formatted,
output: output,
output: output_code,
expected: expect
});
return false;
}
// expect == output
try {
U.parse(output);
output.validate_ast();
U.parse(output_code);
} catch (ex) {
log([
"!!! Test matched expected result but cannot parse output",
@@ -350,7 +350,7 @@ function test_case(test) {
"",
].join("\n"), {
input: input_formatted,
output: output,
output: output_code,
error: ex,
});
return false;
@@ -386,7 +386,7 @@ function test_case(test) {
mangle: test.mangle
});
var actual = stdout[toplevel ? 1 : 0];
if (test.expect_stdout === true) {
if (test.expect_stdout === true || test.expect_stdout instanceof Error && test.expect_stdout.name === actual.name) {
test.expect_stdout = actual;
}
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
@@ -409,7 +409,7 @@ function test_case(test) {
});
return false;
}
actual = run_code(output, toplevel);
actual = run_code(output_code, toplevel);
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
log([
"!!! failed",

View File

@@ -783,3 +783,182 @@ issue_3420_7: {
}
expect_stdout: "true"
}
issue_4200: {
options = {
arguments: true,
keep_fargs: false,
}
input: {
var o = {
get p() {
return arguments[0];
},
};
console.log(o.p);
}
expect: {
var o = {
get p() {
return arguments[0];
},
};
console.log(o.p);
}
expect_stdout: "undefined"
}
issue_4291_1: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(function() {
arguments[0] = "PASS";
return arguments;
}()[0]);
}
expect: {
console.log(function() {
arguments[0] = "PASS";
return arguments;
}()[0]);
}
expect_stdout: "PASS"
}
issue_4291_2: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
var a = function() {
if (arguments[0])
arguments[1] = "PASS";
return arguments;
}(42);
console.log(a[1], a[0], a.length);
}
expect: {
var a = function(argument_0) {
if (argument_0)
arguments[1] = "PASS";
return arguments;
}(42);
console.log(a[1], a[0], a.length);
}
expect_stdout: "PASS 42 1"
}
issue_4397: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(typeof function() {
arguments += 0;
return arguments[0];
}());
}
expect: {
console.log(typeof function() {
arguments += 0;
return arguments[0];
}());
}
expect_stdout: "string"
}
issue_4410_1: {
options = {
arguments: true,
conditionals: true,
evaluate: true,
reduce_vars: true,
}
input: {
(function(a) {
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
})(1);
}
expect: {
(function(a) {
console.log(a === (a = 0) ? "FAIL" : "PASS");
})(1);
}
expect_stdout: "PASS"
}
issue_4410_2: {
options = {
arguments: true,
conditionals: true,
evaluate: true,
reduce_vars: true,
}
input: {
(function f(a) {
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
})(1);
}
expect: {
(function f(a) {
console.log(arguments[0] === (a = 0) ? "FAIL" : "PASS");
})(1);
}
expect_stdout: "PASS"
}
issue_4410_3: {
options = {
arguments: true,
}
input: {
var a = 1;
(function f(b) {
a-- && f();
for (var c = 2; c--;)
switch (arguments[0]) {
case b = 42:
case 42:
console.log("PASS");
}
})(null);
}
expect: {
var a = 1;
(function f(b) {
a-- && f();
for (var c = 2; c--;)
switch (arguments[0]) {
case b = 42:
case 42:
console.log("PASS");
}
})(null);
}
expect_stdout: "PASS"
}
issue_4432: {
options = {
arguments: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
for (a in { FAIL: 42 });
return arguments[0];
}() || "PASS");
}
expect: {
console.log(function(a) {
for (a in { FAIL: 42 });
return arguments[0];
}() || "PASS");
}
expect_stdout: "PASS"
}

589
test/compress/arrows.js Normal file
View File

@@ -0,0 +1,589 @@
no_funarg: {
input: {
(() => console.log(42))();
}
expect_exact: "(()=>console.log(42))();"
expect_stdout: "42"
node_version: ">=4"
}
single_funarg: {
input: {
(a => console.log(a))(42);
}
expect_exact: "(a=>console.log(a))(42);"
expect_stdout: "42"
node_version: ">=4"
}
multiple_funargs: {
input: {
((a, b) => console.log(a, b))("foo", "bar");
}
expect_exact: '((a,b)=>console.log(a,b))("foo","bar");'
expect_stdout: "foo bar"
node_version: ">=4"
}
destructured_funarg: {
input: {
(([ a, b, c ]) => console.log(a, b, c))("foo");
}
expect_exact: '(([a,b,c])=>console.log(a,b,c))("foo");'
expect_stdout: "f o o"
node_version: ">=6"
}
await_parenthesis: {
input: {
async function f() {
await (a => a);
}
}
expect_exact: "async function f(){await(a=>a)}"
}
for_parenthesis_init: {
input: {
for (a => (a in a); console.log(42););
}
expect_exact: "for((a=>a in a);console.log(42););"
expect_stdout: "42"
node_version: ">=4"
}
for_parenthesis_condition: {
input: {
for (console.log(42); a => (a in a);)
break;
}
expect_exact: "for(console.log(42);a=>a in a;)break;"
expect_stdout: "42"
node_version: ">=4"
}
for_parenthesis_step: {
input: {
for (; console.log(42); a => (a in a));
}
expect_exact: "for(;console.log(42);a=>a in a);"
expect_stdout: "42"
node_version: ">=4"
}
for_assign_parenthesis_init: {
input: {
for (f = a => (a in a); console.log(42););
}
expect_exact: "for((f=a=>a in a);console.log(42););"
expect_stdout: "42"
node_version: ">=4"
}
for_assign_parenthesis_condition: {
input: {
for (console.log(42); f = a => (a in a);)
break;
}
expect_exact: "for(console.log(42);f=a=>a in a;)break;"
expect_stdout: "42"
node_version: ">=4"
}
for_assign_parenthesis_step: {
input: {
for (; console.log(42); f = a => (a in a));
}
expect_exact: "for(;console.log(42);f=a=>a in a);"
expect_stdout: "42"
node_version: ">=4"
}
for_declaration_parenthesis_init: {
input: {
for (var f = a => (a in a); console.log(42););
}
expect_exact: "for(var f=(a=>a in a);console.log(42););"
expect_stdout: "42"
node_version: ">=4"
}
for_statement_parenthesis_init: {
input: {
for (a => {
a in a;
}; console.log(42););
}
expect_exact: "for(a=>{a in a};console.log(42););"
expect_stdout: "42"
node_version: ">=4"
}
body_call: {
input: {
(() => {
console.log("foo");
console.log("bar");
})();
}
expect_exact: '(()=>{console.log("foo");console.log("bar")})();'
expect_stdout: [
"foo",
"bar",
]
node_version: ">=4"
}
body_conditional: {
input: {
console.log((a => {}) ? "PASS" : "FAIL");
}
expect_exact: 'console.log((a=>{})?"PASS":"FAIL");'
expect_stdout: "PASS"
node_version: ">=4"
}
destructured_object_value: {
input: {
console.log((a => ({} = a))(42));
}
expect_exact: "console.log((a=>({}=a))(42));"
expect_stdout: "42"
node_version: ">=6"
}
function_value: {
input: {
console.log((a => function() {
return a;
})(42)());
}
expect_exact: "console.log((a=>function(){return a})(42)());"
expect_stdout: "42"
node_version: ">=4"
}
in_value: {
input: {
console.log((a => a in {
foo: 42,
})("foo"));
}
expect_exact: 'console.log((a=>a in{foo:42})("foo"));'
expect_stdout: "true"
node_version: ">=4"
}
object_value: {
input: {
console.log((() => ({
4: 2,
}))()[4]);
}
expect_exact: "console.log((()=>({4:2}))()[4]);"
expect_stdout: "2"
node_version: ">=4"
}
object_first_in_value: {
input: {
console.log((a => ({
p: a,
}.p ? "FAIL" : "PASS"))());
}
expect_exact: 'console.log((a=>({p:a}).p?"FAIL":"PASS")());'
expect_stdout: "PASS"
node_version: ">=4"
}
sequence_value: {
input: {
console.log((a => (console.log("foo"), a))("bar"));
}
expect_exact: 'console.log((a=>(console.log("foo"),a))("bar"));'
expect_stdout: [
"foo",
"bar",
]
node_version: ">=4"
}
side_effects_value: {
options = {
side_effects: true,
}
input: {
console.log((a => function() {
return a;
})(42)());
}
expect: {
console.log((a => function() {
return a;
})(42)());
}
expect_stdout: "42"
node_version: ">=4"
}
arrow_property: {
input: {
console.log((a => 42).prototype);
}
expect_exact: "console.log((a=>42).prototype);"
expect_stdout: "undefined"
node_version: ">=4"
}
assign_arrow: {
input: {
var f = a => a;
console.log(f(42));
}
expect_exact: "var f=a=>a;console.log(f(42));"
expect_stdout: "42"
node_version: ">=4"
}
binary_arrow: {
input: {
console.log(4 || (() => 2));
}
expect_exact: "console.log(4||(()=>2));"
expect_stdout: "4"
node_version: ">=4"
}
unary_arrow: {
input: {
console.log(+(() => 42));
}
expect_exact: "console.log(+(()=>42));"
expect_stdout: "NaN"
node_version: ">=4"
}
trailing_comma: {
input: {
((a,) => console.log(a))(42);
}
expect_exact: "(a=>console.log(a))(42);"
expect_stdout: "42"
node_version: ">=4"
}
drop_arguments: {
options = {
arguments: true,
keep_fargs: false,
}
input: {
console.log(function() {
return () => arguments[0];
}("PASS")("FAIL"));
}
expect: {
console.log(function(argument_0) {
return () => argument_0;
}("PASS")("FAIL"));
}
expect_stdout: "PASS"
node_version: ">=4"
}
funarg_arguments: {
options = {
inline: true,
}
input: {
console.log((arguments => arguments)(42));
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=4"
}
inline_arguments: {
options = {
inline: true,
}
input: {
console.log(function() {
return () => arguments[0];
}("PASS")("FAIL"));
}
expect: {
console.log(function() {
return () => arguments[0];
}("PASS")("FAIL"));
}
expect_stdout: "PASS"
node_version: ">=4"
}
var_arguments: {
options = {
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function() {
return () => {
var arguments = [ "PASS" ];
return arguments;
};
}("FAIL 1")("FAIL 2")[0]);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
negate: {
options = {
conditionals: true,
}
input: {
if (!console ? 0 : () => 1)
console.log("PASS");
}
expect: {
(console ? () => 1 : 0) && console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
inline_this: {
options = {
inline: true,
}
input: {
var o = {
p: function() {
return function() {
return () => this.q;
}();
},
q: "FAIL",
};
q = "PASS";
console.log(o.p()());
}
expect: {
var o = {
p: function() {
return function() {
return () => this.q;
}();
},
q: "FAIL",
};
q = "PASS";
console.log(o.p()());
}
expect_stdout: "PASS"
node_version: ">=4"
}
trim_body: {
options = {
arrows: true,
if_return: true,
side_effects: true,
}
input: {
var f = a => {
return a;
};
var g = b => void b;
console.log(f("PASS"), g("FAIL"));
}
expect: {
var f = a => a;
var g = b => {};
console.log(f("PASS"), g("FAIL"));
}
expect_stdout: "PASS undefined"
node_version: ">=4"
}
collapse_value: {
options = {
arrows: true,
collapse_vars: true,
keep_fargs: "strict",
unused: true,
}
input: {
var a = 42;
console.log((b => Math.floor(b))(a));
}
expect: {
var a = 42;
console.log((() => Math.floor(a))());
}
expect_stdout: "42"
node_version: ">=4"
}
reduce_iife_1: {
options = {
evaluate: true,
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
(a => console.log(a + a))(21);
}
expect: {
(() => console.log(42))();
}
expect_stdout: "42"
node_version: ">=4"
}
reduce_iife_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 21;
(() => console.log(a + a))();
}
expect: {
(() => console.log(42))();
}
expect_stdout: "42"
node_version: ">=4"
}
reduce_iife_3: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "foo";
(() => {
console.log(a);
console.log(a);
})();
a = "bar";
}
expect: {
(() => {
console.log("foo");
console.log("foo");
})();
}
expect_stdout: [
"foo",
"foo",
]
node_version: ">=4"
}
single_use_recursive: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
return (() => f)();
}
console.log(typeof f());
}
expect: {
console.log(typeof function f() {
return (() => f)();
}());
}
expect_stdout: "function"
node_version: ">=4"
}
issue_4388: {
options = {
inline: true,
toplevel: true,
}
input: {
(arguments => console.log(arguments && arguments))();
}
expect: {
(arguments => console.log(arguments && arguments))();
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_4390: {
options = {
collapse_vars: true,
}
input: {
function log() {
console.log.apply(console, arguments);
}
var a = 42, b = "FAIL";
b = "PASS";
(c => log(b, c))(a);
log(b);
}
expect: {
function log() {
console.log.apply(console, arguments);
}
var a = 42, b = "FAIL";
b = "PASS";
(c => log(b, c))(a);
log(b);
}
expect_stdout: [
"PASS 42",
"PASS",
]
node_version: ">=4"
}
issue_4401: {
options = {
merge_vars: true,
}
input: {
(function() {
var a = (b => b(a))(console.log || a);
var c = console.log;
c && c(typeof b);
})();
}
expect: {
(function() {
var a = (b => b(a))(console.log || a);
var c = console.log;
c && c(typeof b);
})();
}
expect_stdout: [
"undefined",
"undefined",
]
node_version: ">=4"
}

View File

@@ -1,35 +0,0 @@
ascii_only_true: {
options = {}
beautify = {
ascii_only : true,
ie8 : false,
beautify : false,
}
input: {
function f() {
return "\x000\x001\x007\x008\x00" +
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
}
}
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
}
ascii_only_false: {
options = {}
beautify = {
ascii_only : false,
ie8 : false,
beautify : false,
}
input: {
function f() {
return "\x000\x001\x007\x008\x00" +
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
}
}
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
}

View File

@@ -76,9 +76,8 @@ asm_mixed: {
start = start | 0;
end = end | 0;
var sum = 0.0, p = 0, q = 0;
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0)
sum = sum + +log(values[p >> 3]);
}
return +sum;
}
function geometricMean(start, end) {
@@ -91,11 +90,12 @@ asm_mixed: {
function no_asm_GeometricMean(stdlib, foreign, buffer) {
function logSum(start, end) {
start |= 0, end |= 0;
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0)
sum += +log(values[p >> 3]);
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 };

642
test/compress/async.js Normal file
View File

@@ -0,0 +1,642 @@
await_await: {
input: {
(async function() {
console.log("PASS");
await await 42;
})();
}
expect: {
(async function() {
console.log("PASS");
await await 42;
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
defun_name: {
input: {
async function await() {
console.log("PASS");
}
await();
}
expect: {
async function await() {
console.log("PASS");
}
await();
}
expect_stdout: "PASS"
node_version: ">=8"
}
nested_await: {
input: {
(async function() {
console.log(function(await) {
return await;
}("PASS"));
})();
}
expect: {
(async function() {
console.log(function(await) {
return await;
}("PASS"));
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
reduce_single_use_defun: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
async function f(a) {
console.log(a);
}
f("PASS");
}
expect: {
(async function(a) {
console.log(a);
})("PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
}
dont_inline: {
options = {
inline: true,
}
input: {
(async function() {
A;
})().catch(function() {});
console.log("PASS");
}
expect: {
(async function() {
A;
})().catch(function() {});
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
}
evaluate: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = async function() {}();
console.log(typeof a);
}
expect: {
var a = async function() {}();
console.log(typeof a);
}
expect_stdout: "object"
node_version: ">=8"
}
negate: {
options = {
side_effects: true,
}
input: {
console && async function() {} && console.log("PASS");
}
expect: {
console && async function() {} && console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=8"
}
negate_iife: {
options = {
negate_iife: true,
}
input: {
(async function() {
console.log("PASS");
})();
}
expect: {
!async function() {
console.log("PASS");
}();
}
expect_stdout: "PASS"
node_version: ">=8"
}
object_function: {
options = {
properties: true,
side_effects: true,
}
input: {
({
async f() {
console.log("PASS");
},
}).f();
}
expect: {
(async function() {
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
collapse_vars_1: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
(async function() {
a = "PASS";
await 42;
return "PASS";
})();
console.log(a);
}
expect: {
var a = "FAIL";
(async function() {
a = "PASS";
await 42;
return "PASS";
})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=8"
}
collapse_vars_2: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
(async function() {
await (a = "PASS");
return "PASS";
})();
console.log(a);
}
expect: {
var a = "FAIL";
(async function() {
await (a = "PASS");
return "PASS";
})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=8"
}
collapse_vars_3: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
(async function() {
await (a = "PASS", 42);
return "PASS";
})();
console.log(a);
}
expect: {
var a = "FAIL";
(async function() {
await (a = "PASS", 42);
return "PASS";
})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4335_1: {
options = {
inline: true,
}
input: {
var await = "PASS";
(async function() {
console.log(function() {
return await;
}());
})();
}
expect: {
var await = "PASS";
(async function() {
console.log(function() {
return await;
}());
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4335_2: {
options = {
inline: true,
}
input: {
(async function() {
console.log(function() {
function await() {}
return "PASS";
}());
})();
}
expect: {
(async function() {
console.log(function() {
function await() {}
return "PASS";
}());
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4337: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
a();
})(async function() {
console.log("PASS");
});
}
expect: {
(function(a) {
(async function() {
console.log("PASS");
})();
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4340: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(async function a(a) {
console.log(a || "PASS");
})();
}
expect: {
(async function a(a) {
console.log(a || "PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
call_expression: {
input: {
console.log(typeof async function(log) {
(await log)("FAIL");
}(console.log).then);
}
expect_exact: 'console.log(typeof async function(log){(await log)("FAIL")}(console.log).then);'
expect_stdout: "function"
node_version: ">=8"
}
property_access_expression: {
input: {
console.log(typeof async function(con) {
(await con).log("FAIL");
}(console).then);
}
expect_exact: 'console.log(typeof async function(con){(await con).log("FAIL")}(console).then);'
expect_stdout: "function"
node_version: ">=8"
}
reduce_iife_1: {
options = {
evaluate: true,
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
(async function(a) {
console.log(a + a);
})(21);
}
expect: {
(async function() {
console.log(42);
})();
}
expect_stdout: "42"
node_version: ">=8"
}
reduce_iife_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 21;
(async function() {
console.log(a + a);
})();
}
expect: {
(async function() {
console.log(42);
})();
}
expect_stdout: "42"
node_version: ">=8"
}
reduce_iife_3: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "foo";
(async function() {
console.log(a);
console.log(await a);
})();
a = "bar";
}
expect: {
var a = "foo";
(async function() {
console.log(a);
console.log(await a);
})();
a = "bar";
}
expect_stdout: "foo"
node_version: ">=8"
}
issue_4347_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "foo";
f();
a = "bar";
f();
async function f() {
console.log(a);
}
}
expect: {
var a = "foo";
f();
a = "bar";
f();
async function f() {
console.log(a);
}
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}
issue_4347_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
(async function() {
throw 42;
a = "FAIL";
})();
console.log(a);
}
expect: {
var a = "PASS";
(async function() {
throw 42;
a = "FAIL";
})();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4349_1: {
input: {
console.log(typeof async function() {
await /abc/;
}().then);
}
expect_exact: "console.log(typeof async function(){await/abc/}().then);"
expect_stdout: "function"
node_version: ">=8"
}
issue_4349_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(typeof async function() {
(function(a) {
this[a];
}(await 0));
}().then);
}
expect: {
console.log(typeof async function() {
(function(a) {
this[a];
}(await 0));
}().then);
}
expect_stdout: "function"
node_version: ">=8"
}
issue_4349_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(typeof function(await) {
return async function(a) {
this[a];
}(await);
}(this).then);
}
expect: {
console.log(typeof function(await) {
return async function(a) {
this[a];
}(await);
}(this).then);
}
expect_stdout: "function"
node_version: ">=8"
}
issue_4359: {
options = {
collapse_vars: true,
unused: true,
}
input: {
try {
(async function(a) {
return a;
})(A);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
(async function(a) {
return a;
})(A);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4377: {
options = {
dead_code: true,
inline: true,
side_effects: true,
}
input: {
console.log(typeof function() {
return function() {
f;
async function f() {}
return f();
}();
}().then);
}
expect: {
console.log(typeof function() {
return f();
async function f() {}
}().then);
}
expect_stdout: "function"
node_version: ">=8"
}
issue_4406: {
options = {
merge_vars: true,
}
input: {
A = "PASS";
B = "FAIL";
(function() {
var a, b;
a = A;
(async function({
[console.log(a)]: {},
}) {})((b = B) && { undefined: b });
})();
}
expect: {
A = "PASS";
B = "FAIL";
(function() {
var a, b;
a = A;
(async function({
[console.log(a)]: {},
}) {})((b = B) && { undefined: b });
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4417: {
options = {
inline: true,
}
input: {
(async function() {
console.log(function() {
return await => 0;
}().prototype);
})();
}
expect: {
(async function() {
console.log(function() {
return await => 0;
}().prototype);
})();
}
expect_stdout: "undefined"
node_version: ">=8"
}

View File

@@ -153,3 +153,31 @@ issue_3690: {
}
expect_stdout: "PASS"
}
issue_4374: {
options = {
booleans: true,
conditionals: true,
if_return: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
console.log(f());
function f(a) {
if (null) return 0;
if (a) return 1;
return 0;
}
})();
}
expect: {
(function() {
console.log(function(a) {
return !null && a ? 1 : 0;
}());
})();
}
expect_stdout: "0"
}

View File

@@ -62,18 +62,18 @@ collapse_vars_side_effects_1: {
expect: {
function f1() {
var s = "abcdef", i = 2;
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
console.log.bind(console)(s.charAt(i++), s.charAt(+i), s.charAt(4), 7);
}
function f2() {
var s = "abcdef", i = 2;
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(i++), 7);
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(+i), 7);
}
function f3() {
var s = "abcdef",
i = 2,
log = console.log.bind(console),
x = s.charAt(i++),
y = s.charAt(i++);
y = s.charAt(+i);
log(x, s.charAt(4), y, 7);
}
function f4() {
@@ -346,9 +346,8 @@ collapse_vars_if: {
return "x" != "Bar" + x / 4 ? g9 : g5;
}
function f3(x) {
if (x) {
if (x)
return 1;
}
return 2;
}
}
@@ -1599,7 +1598,7 @@ collapse_vars_constants: {
}
}
collapse_vars_arguments: {
collapse_vars_arguments_1: {
options = {
booleans: true,
collapse_vars: true,
@@ -1636,6 +1635,78 @@ collapse_vars_arguments: {
expect_stdout: true
}
collapse_vars_arguments_2: {
options = {
collapse_vars: true,
}
input: {
function log(a, b) {
console.log(b);
}
function f(c) {
var d = arguments[0];
c = "FAIL";
log(c, d);
}
f();
f("PASS");
}
expect: {
function log(a, b) {
console.log(b);
}
function f(c) {
var d = arguments[0];
log(c = "FAIL", d);
}
f();
f("PASS");
}
expect_stdout: [
"undefined",
"PASS",
]
}
collapse_vars_arguments_3: {
options = {
collapse_vars: true,
}
input: {
function log(a, b) {
console.log(b);
}
function f(c) {
var args = arguments;
console.log(c);
var d = args[0];
c = "FAIL";
log(c, d);
}
f();
f("PASS");
}
expect: {
function log(a, b) {
console.log(b);
}
function f(c) {
var args = arguments;
console.log(c);
var d = args[0];
log(c = "FAIL", d);
}
f();
f("PASS");
}
expect_stdout: [
"undefined",
"undefined",
"PASS",
"PASS",
]
}
collapse_vars_short_circuit: {
options = {
booleans: true,
@@ -3001,7 +3072,6 @@ issue_2298: {
expect: {
!function() {
(function() {
0;
try {
!function(b) {
(void 0)[1] = "foo";
@@ -4121,9 +4191,8 @@ issue_2436_11: {
if (isCollection(arg1)) {
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
return size && true === size.isMatrix ? matrix(res) : res;
} else {
} else
return _randomInt(min = arg1, max = arg2);
}
}
}
}
@@ -4239,9 +4308,8 @@ issue_2497: {
function sample() {
if (true)
for (var i = 0; i < 1; ++i)
for (var k = 0; k < 1; ++k) {
for (var k = 0; k < 1; ++k)
value = (value = 1) ? value + 1 : 0;
}
else
for (i = 0; i < 1; ++i)
for (k = 0; k < 1; ++k)
@@ -8280,3 +8348,317 @@ issue_3976: {
}
expect_stdout: "PASS"
}
issue_4012: {
options = {
collapse_vars: true,
dead_code: true,
evaluate: true,
}
input: {
(function(a) {
try {
throw 2;
} catch (b) {
a = "PASS";
if (--b)
return;
if (3);
} finally {
console.log(a);
}
})();
}
expect: {
(function(a) {
try {
throw 2;
} catch (b) {
a = "PASS";
if (--b)
return;
if (3);
} finally {
console.log(a);
}
})();
}
expect_stdout: "PASS"
}
global_assign: {
options = {
collapse_vars: true,
}
input: {
this.A = "FAIL";
A = "PASS";
B = "FAIL";
console.log(A);
}
expect: {
this.A = "FAIL";
A = "PASS";
B = "FAIL";
console.log(A);
}
expect_stdout: "PASS"
}
global_read: {
options = {
collapse_vars: true,
}
input: {
var a = 0;
a = this.A;
A = 1;
a ? console.log("FAIL") : console.log("PASS");
}
expect: {
var a = 0;
a = this.A;
A = 1;
a ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4038: {
options = {
collapse_vars: true,
}
input: {
var a = 0;
a = this;
a = a.A;
A = 1;
a ? console.log("FAIL") : console.log("PASS");
}
expect: {
var a = 0;
a = (a = this).A;
A = 1;
a ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4040: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var a = console.log("PASS") && a.p;
delete NaN;
}
expect: {
var a = console.log("PASS") && a.p;
delete NaN;
}
expect_stdout: "PASS"
}
issue_4047_1: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
console.log(+function(a) {
b = a;
(a >>= 0) && console.log("PASS");
}(--b + (0 !== typeof A)));
}
expect: {
var b = 1;
var a;
console.log((a = --b + ((a = 0) !== typeof A), +void ((a >>= 0) && console.log("PASS"))));
}
expect_stdout: [
"PASS",
"NaN",
]
}
issue_4047_2: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
console.log(+function(a) {
b = a;
(a >>= 0) && console.log("PASS");
}(--b + (0 !== typeof A)));
}
expect: {
var a;
console.log((a = +(0 !== typeof A), +void ((a >>= 0) && console.log("PASS"))));
}
expect_stdout: [
"PASS",
"NaN",
]
}
issue_4051: {
options = {
collapse_vars: true,
}
input: {
try {
var a = (b = b.p, "FAIL"), b = b;
} catch (e) {}
console.log(a);
}
expect: {
try {
var a = (b = b.p, "FAIL"), b = b;
} catch (e) {}
console.log(a);
}
expect_stdout: "undefined"
}
issue_4070: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
}
input: {
console.log(function f() {
function g() {}
g.p++;
return f.p = g.p;
}());
}
expect: {
console.log(function f() {
function g() {}
return f.p = ++g.p;
}());
}
expect_stdout: "NaN"
}
issue_4242: {
options = {
collapse_vars: true,
conditionals: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
if (console)
var a = function(){}, b = (!1 === console || a)();
}());
}
expect: {
console.log(function() {
console && (!1 === console || function(){})();
}());
}
expect_stdout: "undefined"
}
issue_4248: {
options = {
collapse_vars: true,
}
input: {
var a = 0;
try {
a = 1;
b[1];
} catch (e) {
console.log(a);
}
}
expect: {
var a = 0;
try {
a = 1;
b[1];
} catch (e) {
console.log(a);
}
}
expect_stdout: "1"
}
issue_4430_1: {
options = {
collapse_vars: true,
pure_getters: "strict",
}
input: {
function f(a) {
switch (a = 1, arguments[0]) {
case 1:
return "PASS";
case 2:
return "FAIL";
}
}
console.log(f(2));
}
expect: {
function f(a) {
switch (a = 1, arguments[0]) {
case 1:
return "PASS";
case 2:
return "FAIL";
}
}
console.log(f(2));
}
expect_stdout: "PASS"
}
issue_4430_2: {
options = {
collapse_vars: true,
pure_getters: "strict",
}
input: {
function f(a) {
switch (a = 0, arguments[0]) {
case 0:
return "PASS";
case 1:
return "FAIL";
}
}
console.log(f(1));
}
expect: {
function f(a) {
switch (arguments[a = 0]) {
case 0:
return "PASS";
case 1:
return "FAIL";
}
}
console.log(f(1));
}
expect_stdout: "PASS"
}

View File

@@ -123,6 +123,29 @@ self_comparison_3: {
]
}
self_comparison_4: {
options = {
booleans: true,
comparisons: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {};
console.log(o == o, o != o);
console.log(o === o, o !== o);
}
expect: {
console.log(!0, !1);
console.log(!0, !1);
}
expect_stdout: [
"true false",
"true false",
]
}
issue_2857_1: {
options = {
comparisons: true,

View File

@@ -238,6 +238,41 @@ concat_8: {
expect_stdout: true
}
concat_9: {
options = {
booleans: true,
evaluate: true,
reduce_vars: true,
strings: true,
toplevel: true,
}
input: {
var a = "foo";
console.log(
12 + (34 + a),
null + (34 + a),
12 + (null + a),
false + (34 + a),
12 + (false + a),
"bar" + (34 + a),
12 + ("bar" + a)
);
}
expect: {
var a = "foo";
console.log(
"1234" + a,
"null34" + a,
"12null" + a,
!1 + (34 + a),
12 + (!1 + a),
"bar34" + a,
"12bar" + a
);
}
expect_stdout: true
}
issue_3689: {
options = {
strings: true,

View File

@@ -55,14 +55,15 @@ ifs_3_should_warn: {
}
input: {
var x, y;
if (x && !(x + "1") && y) { // 1
// 1
if (x && !(x + "1") && y) {
var qq;
foo();
} else {
bar();
}
if (x || !!(x + "1") || y) { // 2
// 2
if (x || !!(x + "1") || y) {
foo();
} else {
var jj;
@@ -71,9 +72,25 @@ ifs_3_should_warn: {
}
expect: {
var x, y;
var qq; bar(); // 1
var jj; foo(); // 2
// 1
var qq; bar();
// 2
foo(); var jj;
}
expect_warnings: [
"WARN: + in boolean context always true [test/compress/conditionals.js:3,18]",
"WARN: Boolean && always false [test/compress/conditionals.js:3,12]",
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
]
}
ifs_4: {
@@ -783,6 +800,28 @@ cond_12: {
}
}
cond_13: {
options = {
conditionals: true,
}
input: {
x ? y(a) : z(a);
x ? y.f(a) : z.f(a);
x ? y.f(a) : z.g(a);
x ? y.f()(a) : z.g()(a);
x ? y.f.u(a) : z.g.u(a);
x ? y.f().u(a) : z.g().u(a);
}
expect: {
(x ? y : z)(a);
(x ? y : z).f(a);
x ? y.f(a) : z.g(a);
(x ? y.f() : z.g())(a);
(x ? y.f : z.g).u(a);
(x ? y.f() : z.g()).u(a);
}
}
ternary_boolean_consequent: {
options = {
booleans: true,
@@ -1137,7 +1176,7 @@ issue_1645_2: {
expect_stdout: true
}
condition_symbol_matches_consequent: {
condition_matches_consequent: {
options = {
conditionals: true,
}
@@ -1166,6 +1205,35 @@ condition_symbol_matches_consequent: {
expect_stdout: "3 7 true 4"
}
condition_matches_alternative: {
options = {
conditionals: true,
}
input: {
function foo(x, y) {
return x.p ? y[0] : x.p;
}
function bar() {
return g ? h : g;
}
var g = 4;
var h = 5;
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
}
expect: {
function foo(x, y) {
return x.p && y[0];
}
function bar() {
return g && h;
}
var g = 4;
var h = 5;
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
}
expect_stdout: "null 0 false 5"
}
delete_conditional_1: {
options = {
booleans: true,

1377
test/compress/const.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -59,6 +59,9 @@ dead_code_2_should_warn: {
f();
}
expect_stdout: true
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
]
node_version: "<=4"
}
@@ -89,11 +92,21 @@ dead_code_constant_boolean_should_warn_more: {
function bar() {}
// nothing for the while
// as for the for, it should keep:
var moo;
var x = 10, y;
var moo;
bar();
}
expect_stdout: true
expect_warnings: [
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
]
node_version: "<=4"
}
@@ -1341,3 +1354,48 @@ issue_3967: {
}
expect_stdout: "PASS"
}
issue_4051: {
options = {
dead_code: true,
}
input: {
try {
delete (A = A);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
delete (A = A);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4366: {
options = {
dead_code: true,
}
input: {
function f() {
return "PASS";
({
p: 42,
get p() {},
});
}
console.log(f());
}
expect: {
function f() {
return "PASS";
}
console.log(f());
}
expect_stdout: "PASS"
node_version: ">=4"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1729,8 +1729,8 @@ chained_3: {
}
expect: {
console.log(function(a, b) {
var c = 2;
b++;
var c = b;
+b;
return c;
}(0, 2));
}
@@ -1997,7 +1997,7 @@ issue_3146_4: {
expect_stdout: "PASS"
}
issue_3192: {
issue_3192_1: {
options = {
unused: true,
}
@@ -2025,6 +2025,26 @@ issue_3192: {
]
}
issue_3192_2: {
options = {
keep_fargs: "strict",
unused: true,
}
input: {
"use strict";
(function(a) {
console.log(a = "foo", arguments[0]);
})("bar");
}
expect: {
"use strict";
(function() {
console.log("foo", arguments[0]);
})("bar");
}
expect_stdout: "foo bar"
}
issue_3233: {
options = {
pure_getters: "strict",
@@ -2161,8 +2181,7 @@ issue_3515_1: {
expect: {
var c = 0;
(function() {
this[c++] = 0;
for (var key20 in !0);
for (var key20 in !(this[c++] = 0));
})();
console.log(c);
}
@@ -2718,7 +2737,7 @@ issue_3962_1: {
0..toString();
} while (0);
if (c) console.log("PASS");
})((a--, 1));
}(1), 0);
void 0;
}
expect_stdout: "PASS"
@@ -2751,7 +2770,7 @@ issue_3962_2: {
0..toString();
} while (0);
if (c) console.log("PASS");
})((a--, 1));
}(1), 0);
}
expect_stdout: "PASS"
}
@@ -2789,3 +2808,348 @@ issue_3986: {
}
expect_stdout: "0"
}
issue_4017: {
options = {
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
var a = 0;
console.log(function f() {
var b = c &= 0;
var c = a++ + (A = a);
var d = c && c[f];
}());
}
expect: {
var a = 0;
console.log(function() {
c &= 0;
var c = (a++, A = a, 0);
}());
}
expect_stdout: "undefined"
}
issue_4025: {
options = {
collapse_vars: true,
evaluate: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0, b = 0, c = 0, d = a++;
try {
var e = console.log(c), f = b;
} finally {
var d = b = 1, d = c + 1;
c = 0;
}
console.log(a, b, d);
}
expect: {
var c = 0;
try {
console.log(c);
} finally {
var d = c + 1;
c = 0;
}
console.log(1, 1, d);
}
expect_stdout: [
"0",
"1 1 1",
]
}
forin_var_1: {
options = {
unused: true,
}
input: {
var k;
for (k in [ 1, 2 ])
console.log(k);
for (k in { PASS: 3 })
console.log(k);
console.log(k);
}
expect: {
for (var k in [ 1, 2 ])
console.log(k);
for (k in { PASS: 3 })
console.log(k);
console.log(k);
}
expect_stdout: [
"0",
"1",
"PASS",
"PASS",
]
}
forin_var_2: {
options = {
unused: true,
}
input: {
console.log(function() {
switch (0) {
case function() {
for (a in 0);
}:
var b = 0;
}
for (var c = 0; a;);
var a;
}());
}
expect: {
console.log(function() {
switch (0) {
case function() {
for (a in 0);
}:
}
for (; a;);
var a;
}());
}
expect_stdout: "undefined"
}
issue_4133: {
options = {
evaluate: true,
merge_vars: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
var b = [ a-- ], c = b && b[c];
console.log(a);
}
expect: {
var b = 1;
console.log(0);
}
expect_stdout: "0"
}
issue_4144: {
options = {
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
var b = console, c = ++b;
})(console.log("PASS"), 0);
}
expect: {
(function(b) {
b = console,
++b;
})(console.log("PASS"));
}
expect_stdout: "PASS"
}
issue_4146: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a, b) {
function g() {}
var a = g;
var c = b;
c.p;
console.log(typeof a);
}
f("FAIL", 42);
}
expect: {
(function(a, b) {
a = function () {};
var c = b;
c.p;
console.log(typeof a);
})(0, 42);
}
expect_stdout: "function"
}
var_catch_redefined: {
options = {
toplevel: true,
unused: true,
}
input: {
var a = "FAIL";
try {
throw "PASS";
} catch (a) {
function f() {
return a;
}
console.log(a);
}
f();
}
expect: {
var a = "FAIL";
try {
throw "PASS";
} catch (a) {
function f() {
return a;
}
console.log(a);
}
f();
}
expect_stdout: "PASS"
}
single_use_catch_redefined: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect_stdout: true
}
issue_4184: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = function() {}, b = [ a, 1 && b, a = {} ];
try {
throw 42;
} catch (a) {
{
console.log(a);
}
}
})();
}
expect: {
(function() {
var b = [ function() {}, 1 && b, {} ];
try {
throw 42;
} catch (a) {
console.log(a);
}
})();
}
expect_stdout: "42"
}
issue_4235: {
options = {
inline: true,
reduce_vars: true,
unused: true,
varify: true,
}
input: {
(function() {
{
const f = 0;
}
(function f() {
var f = console.log(f);
})();
})();
}
expect: {
(function() {
f = console.log(f),
void 0;
var f;
})();
}
expect_stdout: "undefined"
}
issue_4404: {
options = {
pure_getters: "strict",
unused: true,
}
input: {
function f(a) {
arguments[0] = "PASS";
console.log(a);
}
f("FAIL");
}
expect: {
function f(a) {
arguments[0] = "PASS";
console.log(a);
}
f("FAIL");
}
expect_stdout: "PASS"
}
issue_4413: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function f(arguments) {
var arguments = function() {};
return arguments.length;
}());
}
expect: {
console.log(function(arguments) {
return function() {}.length;
}());
}
expect_stdout: "0"
}

View File

@@ -2833,3 +2833,287 @@ issue_3997: {
}
expect_stdout: "string"
}
issue_4035: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var a = 0;
(function() {
var b = --a;
console.log(delete (0 + b));
console.log(delete (1 * b));
console.log(delete (b + 0));
console.log(delete (b - 0));
console.log(delete (b / 1));
})();
}
expect: {
var a = 0;
(function() {
var b = --a;
console.log((0 + b, true));
console.log((1 * b, true));
console.log((0 + b, true));
console.log((b - 0, true));
console.log((b / 1, true));
})();
}
expect_stdout: [
"true",
"true",
"true",
"true",
"true",
]
}
issue_4067: {
options = {
evaluate: true,
reduce_vars: true,
unsafe: true,
}
input: {
(function(a) {
(function(b) {
b[0] += 0;
console.log(+a);
})(a);
})([]);
}
expect: {
(function(a) {
(function(b) {
b[0] += 0;
console.log(+a);
})(a);
})([]);
}
expect_stdout: "NaN"
}
issue_4077: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log((a = []) - (a[0]++, 1) || "PASS");
}
expect: {
console.log((a = []) - (a[0]++, 1) || "PASS");
}
expect_stdout: "PASS"
}
issue_4119_1: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var a, b;
b = a = [];
a[0] += 0;
if (+b + 1) {
console.log("FAIL");
} else {
console.log("PASS");
}
}
expect: {
var a, b;
b = a = [];
a[0] += 0;
+b + 1 ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4119_2: {
options = {
conditionals: true,
evaluate: true,
reduce_vars: true,
unsafe: true,
}
input: {
var a;
(function(b) {
a[0] += 0;
console.log(+b + 1 ? "FAIL" : "PASS");
})(a = []);
}
expect: {
var a;
(function(b) {
a[0] += 0;
console.log(+b + 1 ? "FAIL" : "PASS");
})(a = []);
}
expect_stdout: "PASS"
}
issue_4119_3: {
options = {
conditionals: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var a, b;
b = a = {
p: 42,
};
delete a.p;
console.log(b.p ? "FAIL" : "PASS");
}
expect: {
var a, b;
b = a = {
p: 42,
};
delete a.p;
console.log(b.p ? "FAIL" : "PASS");
}
expect_stdout: "PASS"
}
issue_4119_4: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a, b;
b = a = {
p: 42,
};
delete a.p;
console.log(!b ? "FAIL" : "PASS");
}
expect: {
var a, b;
b = a = {
p: 42,
};
delete a.p;
console.log((b, 0, "PASS"));
}
expect_stdout: "PASS"
}
issue_4214: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f(a) {
return function() {
try {
return a;
} finally {
var b = 0;
}
}(a++ && this());
}
var c = f();
console.log(c);
}
expect: {
var c = function(a) {
return function() {
try {
return a;
} finally {}
}(a++ && this());
}();
console.log(c);
}
expect_stdout: "NaN"
}
issue_4271: {
options = {
evaluate: true,
unsafe: true,
}
input: {
({
p: null,
q: (console.log("foo"), 42),
p: function() {}
})[console.log("bar"), "p"] && console.log("PASS");
}
expect: {
({
p: null,
q: (console.log("foo"), 42),
p: function() {}
})[console.log("bar"), "p"],
console.log("PASS");
}
expect_stdout: [
"foo",
"bar",
"PASS",
]
}
issue_4393: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function f(a) {
a = "PASS";
console.log(arguments[0]);
})("FAIL");
}
expect: {
(function f(a) {
a = "PASS";
console.log(arguments[0]);
})("FAIL");
}
expect_stdout: "PASS"
}
issue_4422: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function f(a) {
a = "FAIL 1";
arguments[0] = "PASS";
return a;
}("FAIL 2"));
}
expect: {
console.log(function(a) {
a = "FAIL 1";
arguments[0] = "PASS";
return a;
}("FAIL 2"));
}
expect_stdout: "PASS"
}

View File

@@ -521,7 +521,7 @@ issue_2531_2: {
options = {
evaluate: true,
inline: true,
passes: 3,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
@@ -556,9 +556,10 @@ issue_2531_3: {
options = {
evaluate: true,
inline: true,
passes: 3,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
@@ -1483,8 +1484,7 @@ issue_2663_2: {
}
expect: {
(function() {
var i;
for (i in { a: 1, b: 2, c: 3 })
for (var i in { a: 1, b: 2, c: 3 })
j = i, console.log(j);
var j;
})();
@@ -2082,7 +2082,7 @@ issue_3016_1: {
var b = 1;
do {
3[b];
} while(0);
} while (0);
console.log(b);
}
expect_stdout: "1"
@@ -2113,7 +2113,7 @@ issue_3016_2: {
do {
a = 3,
a[b];
} while(0);
} while (0);
var a;
console.log(b);
}
@@ -2146,7 +2146,7 @@ issue_3016_2_ie8: {
do {
a = 3,
a[b];
} while(0);
} while (0);
var a;
console.log(b);
}
@@ -2176,7 +2176,7 @@ issue_3016_3: {
var b = 1;
do {
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
} while(b--);
} while (b--);
var a;
}
expect_stdout: [
@@ -2209,7 +2209,7 @@ issue_3016_3_ie8: {
var b = 1;
do {
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
} while(b--);
} while (b--);
var a;
}
expect_stdout: [
@@ -2677,7 +2677,7 @@ cross_references_3: {
};
return Math.square(n) + Math.cube(n);
};
}(Math)(2));
}()(2));
console.log(Math.square(3), Math.cube(3));
}
expect_stdout: [
@@ -3322,9 +3322,7 @@ issue_3506_1: {
}
expect: {
var a = "FAIL";
!function(b) {
b && (a = "PASS");
}(a);
a && (a = "PASS");
console.log(a);
}
expect_stdout: "PASS"
@@ -4747,3 +4745,481 @@ issue_3929: {
}
expect_stdout: "function"
}
issue_4006: {
options = {
dead_code: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var a = 0;
(function() {
(function(b, c) {
for (var k in console.log(c), 0)
return b += 0;
})(0, --a);
return a ? 0 : --a;
})();
}
expect: {
var a = 0;
(function(c) {
for (var k in console.log(c), 0)
return;
})(--a), a || --a;
}
expect_stdout: "-1"
}
issue_4155: {
options = {
functions: true,
inline: true,
merge_vars: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
(function() {
console.log(a);
})(a);
var b = function() {};
b && console.log(typeof b);
})();
}
expect: {
(function() {
void console.log(b);
var b = function() {};
b && console.log(typeof b);
})();
}
expect_stdout: [
"undefined",
"function",
]
}
issue_4159: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 42, c = function(b) {
(b = a) && console.log(a++, b);
}(c = a);
}
expect: {
var a = 42;
(b = a) && console.log(a++, b);
var b;
}
expect_stdout: "42 42"
}
direct_inline: {
options = {
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f(a, b) {
function g(c) {
return c >> 1;
}
return g(a) + g(b);
}
console.log(f(13, 31));
}
expect: {
function f(a, b) {
return (a >> 1) + (b >> 1);
}
console.log(f(13, 31));
}
expect_stdout: "21"
}
direct_inline_catch_redefined: {
options = {
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
function f() {
return a;
}
try {
throw 2;
} catch (a) {
function g() {
return a;
}
console.log(a, f(), g());
}
console.log(a, f(), g());
}
expect: {
var a = 1;
function f() {
return a;
}
try {
throw 2;
} catch (a) {
function g() {
return a;
}
console.log(a, f(), g());
}
console.log(a, a, g());
}
expect_stdout: true
}
issue_4171_1: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
try {
while (a)
var e = function() {};
} catch (e) {
return function() {
return e;
};
}
}(!console));
}
expect: {
console.log(function(a) {
try {
while (a)
var e = function() {};
} catch (e) {
return function() {
return e;
};
}
}(!console));
}
expect_stdout: "undefined"
}
issue_4171_2: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
try {
while (a);
} catch (e) {
return function() {
return e;
};
} finally {
var e = function() {};
}
}(!console));
}
expect: {
console.log(function(a) {
try {
while (a);
} catch (e) {
return function() {
return e;
};
} finally {
function e() {}
}
}(!console));
}
expect_stdout: "undefined"
}
catch_defun: {
mangle = {
toplevel: true,
}
input: {
try {
throw 42;
} catch (a) {
function f() {
return typeof a;
}
}
console.log(f());
}
expect: {
try {
throw 42;
} catch (o) {
function t() {
return typeof o;
}
}
console.log(t());
}
expect_stdout: true
}
catch_no_argname: {
options = {
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
function f() {
return a;
}
try {
throw a;
} catch {
function g() {
return a;
}
console.log(a, f(), g());
}
console.log(a, f(), g());
}
expect: {
var a = "PASS";
try {
throw a;
} catch {
console.log(a, a, a);
}
console.log(a, a, a);
}
expect_stdout: [
"PASS PASS PASS",
"PASS PASS PASS",
]
node_version: ">=10"
}
issue_4186: {
options = {
conditionals: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
unused: true,
}
input: {
console.log(typeof function() {
return function() {
function f() {
if (1)
g();
else
(function() {
return f;
});
}
return f;
function g() {
if (1) {
if (0)
h;
else
h();
var key = 0;
}
}
function h() {
return factory;
}
};
}()());
}
expect: {
console.log(typeof function() {
return function f() {
1 ? void (1 && (0 ? h : h(), 0)) : function() {
return f;
};
};
function h() {
return factory;
}
}());
}
expect_stdout: "function"
}
issue_4233: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
try {
var a = function() {};
try {
throw 42;
} catch (a) {
(function() {
console.log(typeof a);
})();
var a;
}
} catch (e) {}
})();
}
expect: {
(function() {
try {
var a = function() {};
try {
throw 42;
} catch (a) {
(function() {
console.log(typeof a);
})();
var a;
}
} catch (e) {}
})();
}
expect_stdout: "number"
}
issue_4259: {
options = {
collapse_vars: true,
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function b() {
var c = b;
for (b in c);
};
a();
console.log(typeof a);
}
expect: {
function a() {
for (a in a);
}
a();
console.log(typeof a);
}
expect_stdout: "function"
}
issue_4261: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
try {
throw 42;
} catch (e) {
(function() {
function f() {
e.p;
}
function g() {
while (f());
}
(function() {
while (console.log(g()));
})();
})();
}
}
expect: {
try {
throw 42;
} catch (e) {
(function() {
function g() {
while (void e.p);
}
(function() {
while (console.log(g()));
})();
})();
}
}
expect_stdout: true
}
issue_4265: {
options = {
conditionals: true,
dead_code: true,
inline: true,
sequences: true,
}
input: {
function f() {
console;
if ([ function() {
return this + console.log(a);
a;
var a;
}() ]);
return 0;
}
f();
}
expect: {
function f() {
return console, function() {
return console.log(a);
var a;
}(), 0;
}
f();
}
expect_stdout: "undefined"
}
trailing_comma: {
input: {
new function(a, b,) {
console.log(b, a,);
}(42, "PASS",);
}
expect_exact: 'new function(a,b){console.log(b,a)}(42,"PASS");'
expect_stdout: "PASS 42"
}

View File

@@ -12,6 +12,20 @@ must_replace: {
}
}
repeated_nodes: {
options = {
global_defs: {
"@N": "rand()",
},
}
input: {
console.log(N, N);
}
expect: {
console.log(rand(), rand());
}
}
keyword: {
options = {
global_defs: {

View File

@@ -297,6 +297,33 @@ name_collision_3: {
expect_stdout: "true 4 6"
}
name_collision_4: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
console.log(function() {
var o = {
p: 0,
q: "PASS",
};
return function(o_p) {
if (!o.p) return o_p;
}(o.q);
}());
}
expect: {
console.log(function() {
var o_p$0 = 0, o_q = "PASS";
return function(o_p) {
if (!o_p$0) return o_p;
}(o_q);
}());
}
expect_stdout: "PASS"
}
contains_this_1: {
options = {
evaluate: true,
@@ -1016,3 +1043,28 @@ issue_3945_2: {
}
expect_stdout: "undefined"
}
issue_4023: {
options = {
comparisons: true,
hoist_props: true,
inline: true,
reduce_vars: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
function f() {
var a = function() {
return { p: 0 };
}();
return console.log("undefined" != typeof a);
}
f();
}
expect: {
console.log(void 0 !== {});
}
expect_stdout: "true"
}

View File

@@ -588,7 +588,6 @@ issue_3197_1: {
ie8: false,
}
input: {
var window = {};
!function() {
function Foo() {
console.log(this instanceof Foo);
@@ -598,7 +597,6 @@ issue_3197_1: {
new window.Foo();
}
expect: {
var window = {};
window.Foo = function o() {
console.log(this instanceof o);
};
@@ -619,7 +617,6 @@ issue_3197_1_ie8: {
ie8: true,
}
input: {
var window = {};
!function() {
function Foo() {
console.log(this instanceof Foo);
@@ -629,7 +626,6 @@ issue_3197_1_ie8: {
new window.Foo();
}
expect: {
var window = {};
window.Foo = function Foo() {
console.log(this instanceof Foo);
};
@@ -2544,12 +2540,12 @@ issue_3999: {
expect: {
(function() {
(function f() {
for (var c = 0; c < 2; c++)
for (var o = 0; o < 2; o++)
try {
f[0];
} catch (f) {
var f = 0;
console.log(c);
console.log(o);
}
})();
})(typeof f);
@@ -2593,3 +2589,314 @@ issue_4001: {
}
expect_stdout: "undefined"
}
issue_4015: {
rename = true
mangle = {
ie8: true,
toplevel: true,
}
input: {
var n, a = 0, b;
function f() {
try {
throw 0;
} catch (b) {
(function g() {
(function b() {
a++;
})();
})();
}
}
f();
console.log(a);
}
expect: {
var n, o = 0, c;
function t() {
try {
throw 0;
} catch (c) {
(function n() {
(function c() {
o++;
})();
})();
}
}
t();
console.log(o);
}
expect_stdout: "1"
}
issue_4019: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = function() {
try {
console.log("FAIL");
} catch (b) {}
}, a = (console.log(a.length), ++a);
}
expect: {
var o = function() {
try {
console.log("FAIL");
} catch (o) {}
}, o = (console.log(o.length), ++o);
}
expect_stdout: "0"
}
issue_4028: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
ie8: true,
}
input: {
function a() {
try {
A;
} catch (e) {}
}
var b = a += a;
console.log(typeof b);
}
expect: {
function a() {
try {
A;
} catch (a) {}
}
var b = a += a;
console.log(typeof b);
}
expect_stdout: "string"
}
issue_2737: {
options = {
ie8: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
a();
})(function f() {
console.log(typeof f);
});
}
expect: {
(function(a) {
a();
})(function f() {
console.log(typeof f);
});
}
expect_stdout: "function"
}
single_use_catch_redefined: {
options = {
ie8: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect_stdout: true
}
single_use_inline_catch_redefined: {
options = {
ie8: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect: {
var a = 1;
try {
throw 2;
} catch (a) {
function g() {
return a;
}
}
console.log(g());
}
expect_stdout: true
}
direct_inline_catch_redefined: {
options = {
ie8: true,
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
function f() {
return a;
}
try {
throw 2;
} catch (a) {
function g() {
return a;
}
console.log(a, f(), g());
}
console.log(a, f(), g());
}
expect: {
var a = 1;
function f() {
return a;
}
try {
throw 2;
} catch (a) {
function g() {
return a;
}
console.log(a, f(), g());
}
console.log(a, a, g());
}
expect_stdout: true
}
issue_4186: {
options = {
dead_code: true,
evaluate: true,
ie8: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
function f() {
(function NaN() {
var a = 1;
while (a--)
try {} finally {
console.log(0/0);
var b;
}
})(f);
}
f();
NaN;
}
expect: {
(function() {
(function NaN() {
var n = 1;
while (n--)
console.log(0/0);
})();
})();
NaN;
}
expect_stdout: "NaN"
}
issue_4235: {
options = {
ie8: true,
unused: true,
}
input: {
try {} catch (e) {}
console.log(function e() {
var e = 0;
}());
}
expect: {
try {} catch (e) {}
console.log(function e() {}());
}
expect_stdout: "undefined"
}
issue_4250: {
options = {
ie8: true,
loops: true,
unused: true,
}
input: {
console.log(function f() {
(function() {
for (f in "f");
})();
return f;
var f;
}());
}
expect: {
console.log(function f() {
(function() {
for (f in "f");
})();
return f;
var f;
}());
}
expect_stdout: "0"
}

View File

@@ -594,3 +594,157 @@ iife_if_return_simple: {
}
expect_stdout: "PASS"
}
nested_if_break: {
options = {
if_return: true,
}
input: {
for (var i = 0; i < 3; i++)
L1: if ("number" == typeof i) {
if (0 === i) break L1;
console.log(i);
}
}
expect: {
for (var i = 0; i < 3; i++)
L1: if ("number" == typeof i)
if (0 !== i) console.log(i);
}
expect_stdout: [
"1",
"2",
]
}
nested_if_continue: {
options = {
conditionals: true,
if_return: true,
join_vars: true,
loops: true,
}
input: {
function f(n) {
var i = 0;
do {
if ("number" == typeof n) {
if (0 === n) {
console.log("even", i);
continue;
}
if (1 === n) {
console.log("odd", i);
continue;
}
i++;
}
} while (0 <= (n -= 2));
}
f(37);
f(42);
}
expect: {
function f(n) {
for (var i = 0;
"number" == typeof n
&& (0 !== n
? 1 !== n
? i++
: console.log("odd", i)
: console.log("even", i)),
0 <= (n -= 2););
}
f(37);
f(42);
}
expect_stdout: [
"odd 18",
"even 21",
]
}
nested_if_return: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f() {
if (A) {
if (B)
return B;
if (C)
return D;
if (E)
return F;
if (G)
return H;
if (I) {
if (J)
return K;
return;
}
if (L) {
if (M)
return;
return N;
}
}
}
}
expect: {
function f() {
if (A)
return B || (C ? D : E ? F : G ? H : I ? J ? K : void 0 : L && !M ? N : void 0);
}
}
}
issue_866_1: {
options = {
conditionals: true,
if_return: true,
sequences: false,
};
input: {
function f(a) {
if (a)
return "";
console.log(a);
}
}
expect: {
function f(a) {
if (a)
return "";
console.log(a);
}
}
}
issue_866_2: {
options = {
conditionals: true,
if_return: true,
sequences: true,
}
input: {
(function() {
if (a)
if (b)
c;
else
return d;
})();
}
expect: {
(function() {
if (a) {
if (!b)
return d;
c;
}
})();
}
}

View File

@@ -39,7 +39,7 @@ non_hoisted_function_after_return: {
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]",
]
}
@@ -84,19 +84,16 @@ non_hoisted_function_after_return_2a: {
}
}
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:4,16]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
"INFO: pass 0: last_count: Infinity, count: 36",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"INFO: pass 0: last_count: Infinity, count: 35",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
"INFO: pass 1: last_count: 36, count: 18",
"INFO: pass 1: last_count: 35, count: 18",
]
}
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
}
}
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
]
}
@@ -242,19 +236,16 @@ non_hoisted_function_after_return_2a_strict: {
}
expect_stdout: "5 6"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:5,16]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
"INFO: pass 0: last_count: Infinity, count: 47",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
"INFO: pass 0: last_count: Infinity, count: 46",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
"INFO: pass 1: last_count: 47, count: 29",
"INFO: pass 1: last_count: 46, count: 29",
]
}
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
}
expect_stdout: "5 6"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
]
}

View File

@@ -16,7 +16,7 @@ multiple_functions: {
( function() {
// NOTE: other compression steps will reduce this
// down to just `window`.
if ( window );
if ( !window );
function f() {}
function g() {}
} )();
@@ -38,7 +38,7 @@ single_function: {
}
expect: {
( function() {
if ( window );
if ( !window );
function f() {}
} )();
}
@@ -67,7 +67,7 @@ deeply_nested: {
// NOTE: other compression steps will reduce this
// down to just `window`.
if ( window )
if (document);
if ( !document );
function f() {}
function g() {}
function h() {}

View File

@@ -151,15 +151,18 @@ Infinity_not_in_with_scope: {
unused: true,
}
input: {
var o = { Infinity: 'oInfinity' };
var o = { Infinity: "FAIL" };
var vInfinity = "Infinity";
vInfinity = Infinity;
console.log(vInfinity);
}
expect: {
var o = { Infinity: 'oInfinity' }
var vInfinity = "Infinity"
vInfinity = 1/0
var o = { Infinity: "FAIL" };
var vInfinity = "Infinity";
vInfinity = 1/0;
console.log(vInfinity);
}
expect_stdout: "Infinity"
}
Infinity_in_with_scope: {
@@ -167,15 +170,18 @@ Infinity_in_with_scope: {
unused: true,
}
input: {
var o = { Infinity: 'oInfinity' };
var o = { Infinity: "PASS" };
var vInfinity = "Infinity";
with (o) { vInfinity = Infinity; }
console.log(vInfinity);
}
expect: {
var o = { Infinity: 'oInfinity' }
var vInfinity = "Infinity"
with (o) vInfinity = Infinity
var o = { Infinity: "PASS" };
var vInfinity = "Infinity";
with (o) vInfinity = Infinity;
console.log(vInfinity);
}
expect_stdout: "PASS"
}
assorted_Infinity_NaN_undefined_in_with_scope: {

View File

@@ -277,8 +277,8 @@ join_object_assignments_forin: {
}
expect: {
console.log(function() {
var o = { a: "PASS" };
for (var a in o)
var o = { a: "PASS" }, a;
for (a in o)
return o[a];
}());
}

View File

@@ -306,7 +306,6 @@ issue_2298: {
expect: {
!function() {
(function() {
0;
try {
!function() {
(void 0)[1] = "foo";
@@ -526,7 +525,7 @@ issue_2506: {
function f0(bar) {
(function() {
(function() {
if (false <= 0/0 & this >> 1 >= 0)
if (false <= NaN & this >> 1 >= 0)
c++;
})(c++);
})();
@@ -1453,3 +1452,37 @@ issue_3619: {
}
expect_stdout: "PASS"
}
issue_4353_1: {
options = {
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
console.log(function f(a) {}.length);
}
expect: {
console.log(function(a) {}.length);
}
expect_stdout: "1"
}
issue_4353_2: {
options = {
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
while (console.log("PASS"));
})();
}
expect: {
(function() {
while (console.log("PASS"));
})();
}
expect_stdout: "PASS"
}

1230
test/compress/let.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -201,7 +201,7 @@ evaluate: {
}
}
issue_1532: {
issue_1532_1: {
options = {
evaluate: true,
loops: true,
@@ -210,18 +210,56 @@ issue_1532: {
function f(x, y) {
do {
if (x) break;
foo();
console.log(y);
} while (false);
}
f(null, "PASS");
f(42, "FAIL");
}
expect: {
function f(x, y) {
for (; !x && (console.log(y), false););
}
f(null, "PASS");
f(42, "FAIL");
}
expect_stdout: "PASS"
}
issue_1532_2: {
options = {
evaluate: true,
loops: true,
}
input: {
function f(x, y) {
do {
if (x) {
console.log(x);
break;
}
console.log(y);
} while (false);
}
f(null, "PASS");
f(42, "FAIL");
}
expect: {
function f(x, y) {
do {
if (x) break;
foo();
} while (false);
if (x) {
console.log(x);
break;
}
} while (console.log(y), false);
}
f(null, "PASS");
f(42, "FAIL");
}
expect_stdout: [
"PASS",
"42",
]
}
issue_186: {
@@ -509,8 +547,8 @@ dead_code_condition: {
console.log(a);
}
expect: {
var c;
var a = 0, b = 5;
var c;
a += 1, 0,
console.log(a);
}
@@ -756,7 +794,37 @@ empty_for_in_side_effects: {
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]",
"WARN: Side effects in object of for-in loop [test/compress/loops.js:2,17]",
]
}
empty_for_in_prop_init: {
options = {
loops: true,
pure_getters: "strict",
unused: true,
}
input: {
console.log(function f() {
var a = "bar";
for ((a, f)[a] in console.log("foo"));
return a;
}());
}
expect: {
console.log(function() {
var a = "bar";
console.log("foo");
return a;
}());
}
expect_stdout: [
"foo",
"bar",
]
expect_warnings: [
"INFO: Dropping unused loop variable f [test/compress/loops.js:3,21]",
"WARN: Side effects in object of for-in loop [test/compress/loops.js:3,30]",
]
}
@@ -933,3 +1001,282 @@ issue_3634_2: {
}
expect_stdout: "1"
}
issue_4075: {
options = {
loops: true,
unused: true,
}
input: {
var a = "FAIL";
(function() {
for (a in { PASS: 0 });
})()
console.log(a);
}
expect: {
var a = "FAIL";
(function() {
for (a in { PASS: 0 });
})()
console.log(a);
}
expect_stdout: "PASS"
}
issue_4082: {
options = {
keep_fargs: "strict",
loops: true,
unused: true,
}
input: {
var a = "PASS";
(function(a) {
for (a in "foo")
var b;
})();
console.log(a);
}
expect: {
var a = "PASS";
(function(a) {
for (a in "foo");
})();
console.log(a);
}
expect_stdout: "PASS"
}
issue_4084: {
options = {
keep_fargs: "strict",
loops: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
function f(a) {
var b = a++;
for (a in "foo");
}
f();
return typeof a;
}());
}
expect: {
console.log(function() {
(function() {
0;
})();
return typeof a;
}());
}
expect_stdout: "undefined"
}
issue_4091_1: {
options = {
loops: true,
toplevel: true,
unused: true,
}
input: {
try {
throw "FAIL";
} catch (e) {
for (var e in 42);
}
console.log(e && e);
}
expect: {
try {
throw "FAIL";
} catch (e) {
var e;
}
console.log(e && e);
}
expect_stdout: "undefined"
}
issue_4091_2: {
options = {
loops: true,
toplevel: true,
unused: true,
}
input: {
try {
throw "FAIL";
} catch (e) {
for (e in 42);
var e;
}
console.log(e && e);
}
expect: {
try {
throw "FAIL";
} catch (e) {
var e;
}
console.log(e && e);
}
expect_stdout: "undefined"
}
issue_4182_1: {
options = {
loops: true,
}
input: {
(function() {
do {
try {
return;
} finally {
continue;
}
console.log("FAIL");
} while (0);
console.log("PASS");
})();
}
expect: {
(function() {
do {
try {
return;
} finally {
continue;
}
console.log("FAIL");
} while (0);
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_4182_2: {
options = {
loops: true,
}
input: {
(function() {
L: do {
do {
try {
return;
} finally {
continue L;
}
console.log("FAIL");
} while (0);
console.log("FAIL");
} while (0);
console.log("PASS");
})();
}
expect: {
(function() {
L: do {
do {
try {
return;
} finally {
continue L;
}
} while (console.log("FAIL"), 0);
console.log("FAIL");
} while (0);
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
do_continue: {
options = {
loops: true,
}
input: {
try {
do {
continue;
} while ([ A ]);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
do {
continue;
} while ([ A ]);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4240: {
options = {
loops: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
function f() {
var o = { PASS: 42 };
for (a in o);
}
(function() {
if (f());
})();
console.log(a);
})();
}
expect: {
(function(a) {
(function() {
if (function() {
for (a in { PASS: 42 });
}());
})();
console.log(a);
})();
}
expect_stdout: "PASS"
}
issue_4355: {
options = {
dead_code: true,
evaluate: true,
loops: true,
side_effects: true,
unused: true,
}
input: {
while (function() {
var a;
for (a in console.log("PASS"))
var b = 0;
}())
var c;
}
expect: {
(function() {
console.log("PASS");
})();
var c;
}
expect_stdout: "PASS"
}

3185
test/compress/merge_vars.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +1,100 @@
hex_numbers_in_parentheses_for_prototype_functions: {
parentheses_for_prototype_functions: {
beautify = {
beautify: true,
}
input: {
function f() {
(-2);
(-2).toFixed(0);
(function() {
console.log((-2));
console.log((-2).toFixed(0));
(2);
(2).toFixed(0);
console.log((2));
console.log((2).toFixed(0));
(0.2);
(0.2).toFixed(0);
console.log((0.2));
console.log((0.2).toFixed(0));
(2.34e20);
(2.34e20).toFixed(0);
console.log((2.34e20));
console.log((2.34e20).toFixed(0));
(0.00000002);
(0.00000002).toFixed(0);
console.log((0.00000002));
console.log((0.00000002).toFixed(0));
(1000000000000000128);
(1000000000000000128).toFixed(0);
console.log((1000000000000000128));
console.log((1000000000000000128).toFixed(0));
(-1000000000000000128);
(-1000000000000000128).toFixed(0);
}
console.log((-1000000000000000128));
console.log((-1000000000000000128).toFixed(0));
})();
}
expect_exact: [
"function f() {",
" -2;",
" (-2).toFixed(0);",
" 2;",
" 2..toFixed(0);",
" .2;",
" .2.toFixed(0);",
" 234e18;",
" 234e18.toFixed(0);",
" 2e-8;",
" 2e-8.toFixed(0);",
" 0xde0b6b3a7640080;",
" (0xde0b6b3a7640080).toFixed(0);",
" -0xde0b6b3a7640080;",
" (-0xde0b6b3a7640080).toFixed(0);",
"}",
"(function() {",
" console.log(-2);",
" console.log((-2).toFixed(0));",
" console.log(2);",
" console.log(2..toFixed(0));",
" console.log(.2);",
" console.log(.2.toFixed(0));",
" console.log(234e18);",
" console.log(234e18.toFixed(0));",
" console.log(2e-8);",
" console.log(2e-8.toFixed(0));",
" console.log(0xde0b6b3a7640080);",
" console.log(0xde0b6b3a7640080.toFixed(0));",
" console.log(-0xde0b6b3a7640080);",
" console.log((-0xde0b6b3a7640080).toFixed(0));",
"})();",
]
expect_stdout: true
}
parentheses_for_prototype_functions_galio: {
beautify = {
beautify: true,
galio: true,
}
input: {
(function() {
console.log((-2));
console.log((-2).toFixed(0));
console.log((2));
console.log((2).toFixed(0));
console.log((0.2));
console.log((0.2).toFixed(0));
console.log((2.34e20));
console.log((2.34e20).toFixed(0));
console.log((0.00000002));
console.log((0.00000002).toFixed(0));
console.log((1000000000000000128));
console.log((1000000000000000128).toFixed(0));
console.log((-1000000000000000128));
console.log((-1000000000000000128).toFixed(0));
})();
}
expect_exact: [
"(function() {",
" console.log(-2);",
" console.log((-2).toFixed(0));",
" console.log(2);",
" console.log(2..toFixed(0));",
" console.log(.2);",
" console.log(.2.toFixed(0));",
" console.log(234e18);",
" console.log(234e18.toFixed(0));",
" console.log(2e-8);",
" console.log(2e-8.toFixed(0));",
" console.log(0xde0b6b3a7640080);",
" console.log((0xde0b6b3a7640080).toFixed(0));",
" console.log(-0xde0b6b3a7640080);",
" console.log((-0xde0b6b3a7640080).toFixed(0));",
"})();",
]
expect_stdout: true
}
comparisons: {
@@ -91,7 +142,7 @@ evaluate_1: {
expect: {
console.log(
x + 1 + 2,
2 * x,
2 * +x,
+x + 1 + 2,
1 + x + 2 + 3,
3 | x,
@@ -130,7 +181,7 @@ evaluate_1_unsafe_math: {
expect: {
console.log(
x + 1 + 2,
2 * x,
2 * +x,
+x + 3,
1 + x + 2 + 3,
3 | x,
@@ -148,45 +199,52 @@ evaluate_1_unsafe_math: {
evaluate_2: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: false,
}
input: {
var x = "42", y = null;
[
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var x = "" + num, y = null;
[
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect: {
var x = "42", y = null;
[
x + 1 + 2,
2 * x,
+x + 1 + 2,
1 + x + 2 + 3,
3 | x,
1 + x-- + 2 + 3,
x*y + 2 + 1 + 3,
1 + (2 + x + 3),
2 + ~x + 3 + 1,
2 + ~x + 3 - y,
0 & x,
2 + (x |= 0) + 3 + 1,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var x = "" + num, y = null;
[
x + "12",
2 * x,
+x + 1 + 2,
1 + x + "23",
3 | x,
1 + x-- + 2 + 3,
x*y + 2 + 1 + 3,
2 + x + 3 + 1,
2 + ~x + 3 + 1,
2 + ~x + 3,
0 & x,
2 + (x |= 0) + 3 + 1,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect_stdout: [
"string 4212",
@@ -207,45 +265,52 @@ evaluate_2: {
evaluate_2_unsafe_math: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: true,
}
input: {
var x = "42", y = null;
[
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var x = "" + num, y = null;
[
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect: {
var x = "42", y = null;
[
x + 1 + 2,
2 * x,
+x + 3,
1 + x + 2 + 3,
3 | x,
6 + x--,
x*y + 6,
1 + (2 + x + 3),
6 + ~x,
5 + ~x - y,
0 & x,
6 + (x |= 0),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var x = "" + num, y = null;
[
x + "12",
2 * x,
+x + 3,
1 + x + "23",
3 | x,
6 + x--,
x*y + 6,
6 + x,
6 + ~x,
5 + ~x,
0 & x,
6 + (x |= 0),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect_stdout: [
"string 4212",
@@ -310,45 +375,52 @@ evaluate_4: {
evaluate_5: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: false,
}
input: {
var a = "1";
[
+a + 2 + 3,
+a + 2 - 3,
+a - 2 + 3,
+a - 2 - 3,
2 + +a + 3,
2 + +a - 3,
2 - +a + 3,
2 - +a - 3,
2 + 3 + +a,
2 + 3 - +a,
2 - 3 + +a,
2 - 3 - +a,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var a = "" + num;
[
+a + 2 + 3,
+a + 2 - 3,
+a - 2 + 3,
+a - 2 - 3,
2 + +a + 3,
2 + +a - 3,
2 - +a + 3,
2 - +a - 3,
2 + 3 + +a,
2 + 3 - +a,
2 - 3 + +a,
2 - 3 - +a,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(1);
}
expect: {
var a = "1";
[
+a + 2 + 3,
+a + 2 - 3,
a - 2 + 3,
a - 2 - 3,
+a + 2 + 3,
+a + 2 - 3,
2 - a + 3,
2 - a - 3,
+a + 5,
5 - a,
+a - 1,
-1 - a,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var a = "" + num;
[
+a + 2 + 3,
+a + 2 - 3,
a - 2 + 3,
a - 2 - 3,
+a + 2 + 3,
+a + 2 - 3,
2 - a + 3,
2 - a - 3,
+a + 5,
5 - a,
+a - 1,
-1 - a,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(1);
}
expect_stdout: [
"number 6",
@@ -369,45 +441,52 @@ evaluate_5: {
evaluate_5_unsafe_math: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: true,
}
input: {
var a = "1";
[
+a + 2 + 3,
+a + 2 - 3,
+a - 2 + 3,
+a - 2 - 3,
2 + +a + 3,
2 + +a - 3,
2 - +a + 3,
2 - +a - 3,
2 + 3 + +a,
2 + 3 - +a,
2 - 3 + +a,
2 - 3 - +a,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var a = "" + num;
[
+a + 2 + 3,
+a + 2 - 3,
+a - 2 + 3,
+a - 2 - 3,
2 + +a + 3,
2 + +a - 3,
2 - +a + 3,
2 - +a - 3,
2 + 3 + +a,
2 + 3 - +a,
2 - 3 + +a,
2 - 3 - +a,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(1);
}
expect: {
var a = "1";
[
+a + 5,
+a + -1,
a - -1,
a - 5,
+a + 5,
+a + -1,
5 - a,
-1 - a,
+a + 5,
5 - a,
+a - 1,
-1 - a,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num) {
var a = "" + num;
[
+a + 5,
+a + -1,
a - -1,
a - 5,
+a + 5,
+a + -1,
5 - a,
-1 - a,
+a + 5,
5 - a,
+a - 1,
-1 - a,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(1);
}
expect_stdout: [
"number 6",
@@ -546,37 +625,44 @@ evaluate_6_unsafe_math: {
evaluate_7: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: false,
}
input: {
var x = "42", y;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
+x - 2 + (3 + !y),
+x - 2 + (3 - !y),
+x - 2 - (3 + !y),
+x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num, y) {
var x = "" + num;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
+x - 2 + (3 + !y),
+x - 2 + (3 - !y),
+x - 2 - (3 + !y),
+x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect: {
var x = "42", y;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
x - 2 + (3 + !y),
x - 2 + (3 - !y),
x - 2 - (3 + !y),
x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num, y) {
var x = "" + num;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
x - 2 + (3 + !y),
x - 2 + (3 - !y),
x - 2 - (3 + !y),
x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect_stdout: [
"number 48",
@@ -593,37 +679,44 @@ evaluate_7: {
evaluate_7_unsafe_math: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_math: true,
}
input: {
var x = "42", y;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
+x - 2 + (3 + !y),
+x - 2 + (3 - !y),
+x - 2 - (3 + !y),
+x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num, y) {
var x = "" + num;
[
+x + 2 + (3 + !y),
+x + 2 + (3 - !y),
+x + 2 - (3 + !y),
+x + 2 - (3 - !y),
+x - 2 + (3 + !y),
+x - 2 + (3 - !y),
+x - 2 - (3 + !y),
+x - 2 - (3 - !y),
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect: {
var x = "42", y;
[
+x + 5 + !y,
+x + 5 - !y,
+x + -1 - !y,
+x + -1 + !y,
x - -1 + !y,
x - -1 - !y,
x - 5 - !y,
x - 5 + !y,
].forEach(function(n) {
console.log(typeof n, n);
});
function f(num, y) {
var x = "" + num;
[
+x + 5 + !y,
+x + 5 - !y,
+x + -1 - !y,
+x + -1 + !y,
x - -1 + !y,
x - -1 - !y,
x - 5 - !y,
x - 5 + !y,
].forEach(function(n) {
console.log(typeof n, n);
});
}
f(42);
}
expect_stdout: [
"number 48",
@@ -637,6 +730,22 @@ evaluate_7_unsafe_math: {
]
}
evaluate_8_unsafe_math: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
var a = [ "42" ];
console.log(a * (1 / 7));
}
expect: {
var a = [ "42" ];
console.log(+a / 7);
}
expect_stdout: "6"
}
NaN_redefined: {
options = {
evaluate: true,
@@ -1251,3 +1360,29 @@ issue_3695: {
}
expect_stdout: "NaN"
}
issue_4137: {
options = {
evaluate: true,
}
input: {
console.log(+(A = []) * (A[0] = 1));
}
expect: {
console.log(+(A = []) * (A[0] = 1));
}
expect_stdout: "0"
}
issue_4142: {
options = {
evaluate: true,
}
input: {
console.log("" + +(0 === console));
}
expect: {
console.log("" + +(0 === console));
}
expect_stdout: "0"
}

View File

@@ -45,8 +45,8 @@ duplicate_key_strict: {
"use strict";
var o = {
a: 1,
b: 2,
a: 3,
b: 2,
};
for (var k in o)
console.log(k, o[k]);
@@ -221,3 +221,237 @@ numeric_literal: {
"8 7 8",
]
}
evaluate_computed_key: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
["foo" + "bar"]: "PASS",
}.foobar);
}
expect: {
console.log({
foobar: "PASS",
}.foobar);
}
expect_stdout: "PASS"
node_version: ">=4"
}
keep_computed_key: {
options = {
side_effects: true,
}
input: {
({
[console.log("PASS")]: 42,
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
shorthand_keywords: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var async = 1, get = 2, set = 3, o = {
async,
get,
set,
};
console.log(o.async, o.get, o.set);
}
expect: {
console.log(1, 2, 3);
}
expect_stdout: "1 2 3"
node_version: ">=6"
}
issue_4269_1: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
get 0() {
return "FAIL";
},
[0]: "PASS",
}[0]);
}
expect: {
console.log({
get 0() {
return "FAIL";
},
[0]: "PASS",
}[0]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4269_2: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
get [0]() {
return "FAIL";
},
0: "PASS",
}[0]);
}
expect: {
console.log({
get [0]() {
return "FAIL";
},
0: "PASS",
}[0]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4269_3: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
["foo"]: "bar",
get 42() {
return "FAIL";
},
42: "PASS",
}[42]);
}
expect: {
console.log({
foo: "bar",
get [42]() {
return "FAIL";
},
42: "PASS",
}[42]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4269_4: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
get 42() {
return "FAIL";
},
["foo"]: "bar",
42: "PASS",
}[42]);
}
expect: {
console.log({
get 42() {
return "FAIL";
},
foo: "bar",
[42]: "PASS",
}[42]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4269_5: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
get 42() {
return "FAIL";
},
[console]: "bar",
42: "PASS",
}[42]);
}
expect: {
console.log({
get 42() {
return "FAIL";
},
[console]: "bar",
42: "PASS",
}[42]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4380: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
get 0() {
return "FAIL 1";
},
0: "FAIL 2",
[0]: "PASS",
}[0]);
}
expect: {
console.log({
get 0() {
return "FAIL 1";
},
[0]: ("FAIL 2", "PASS"),
}[0]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4415: {
options = {
evaluate: true,
objects: true,
}
input: {
console.log({
["00"]: "FAIL",
}[0] || "PASS");
}
expect: {
console.log({
"00": "FAIL",
}[0] || "PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -130,7 +130,7 @@ evaluate_string_length: {
}
}
mangle_properties: {
mangle_properties_1: {
mangle = {
properties: {
keep_quoted: false,
@@ -152,6 +152,53 @@ mangle_properties: {
}
}
mangle_properties_2: {
mangle = {
properties: {
reserved: [
"value",
]
},
}
input: {
var o = {
prop1: 1,
};
Object.defineProperty(o, "prop2", {
value: 2,
});
Object.defineProperties(o, {
prop3: {
value: 3,
},
});
console.log("prop1", o.prop1, "prop1" in o);
console.log("prop2", o.prop2, o.hasOwnProperty("prop2"));
console.log("prop3", o.prop3, Object.getOwnPropertyDescriptor(o, "prop3").value);
}
expect: {
var o = {
o: 1,
};
Object.defineProperty(o, "p", {
value: 2,
});
Object.defineProperties(o, {
r: {
value: 3,
},
});
console.log("prop1", o.o, "o" in o);
console.log("prop2", o.p, o.hasOwnProperty("p"));
console.log("prop3", o.r, Object.getOwnPropertyDescriptor(o, "r").value);
}
expect_stdout: [
"prop1 1 true",
"prop2 2 true",
"prop3 3 3",
]
}
mangle_unquoted_properties: {
options = {
evaluate: true,
@@ -1076,11 +1123,7 @@ new_this: {
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
expect: {}
}
issue_2513: {

View File

@@ -848,9 +848,8 @@ collapse_vars_1_true: {
}
expect: {
function f(a, b) {
for (;;) {
for (;;)
if (a.g() || b.p) break;
}
}
}
}

View File

@@ -120,7 +120,7 @@ modified: {
expect: {
function f0() {
var b = 2;
b++;
+b;
console.log(2);
console.log(4);
}
@@ -1624,7 +1624,7 @@ defun_label: {
expect_stdout: true
}
double_reference: {
double_reference_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
@@ -1638,6 +1638,32 @@ double_reference: {
g();
}
}
expect: {
function f() {
var g = function g() {
g();
};
g();
}
}
}
double_reference_2: {
options = {
functions: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
var g = function g() {
g();
};
g();
}
}
expect: {
function f() {
(function g() {
@@ -1647,6 +1673,60 @@ double_reference: {
}
}
double_reference_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var x = function f() {
return f;
};
function g() {
return x();
}
console.log(g() === g());
}
expect: {
var x = function f() {
return f;
};
function g() {
return x();
}
console.log(g() === g());
}
expect_stdout: "true"
}
double_reference_4: {
options = {
comparisons: true,
functions: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var x = function f() {
return f;
};
function g() {
return x();
}
console.log(g() === g());
}
expect: {
console.log(true);
}
expect_stdout: "true"
}
iife_arguments_1: {
options = {
reduce_funcs: true,
@@ -1686,8 +1766,35 @@ iife_arguments_2: {
}
expect: {
(function() {
console.log(function f() {
var x = function f() {
return f;
};
console.log(x() === arguments[0]);
})();
}
expect_stdout: true
}
iife_arguments_3: {
options = {
functions: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var x = function f() {
return f;
};
console.log(x() === arguments[0]);
})();
}
expect: {
(function() {
console.log(function x() {
return x;
}() === arguments[0]);
})();
}
@@ -1892,7 +1999,7 @@ issue_1606: {
var a, b;
function g(){};
b = 2;
x(b);
x(2);
}
}
}
@@ -2031,6 +2138,7 @@ issue_1670_4: {
issue_1670_5: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
keep_fargs: false,
@@ -2062,11 +2170,13 @@ issue_1670_5: {
issue_1670_6: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
switches: true,
unused: true,
@@ -2084,10 +2194,9 @@ issue_1670_6: {
})(1);
}
expect: {
(function(a) {
a = 1;
console.log(a);
})(1);
(function() {
console.log(1);
})();
}
expect_stdout: "1"
}
@@ -2306,7 +2415,7 @@ redefine_farg_2: {
console.log(typeof [], "number",function(a, b) {
a = b;
return typeof a;
}([]));
}());
}
expect_stdout: "object number undefined"
}
@@ -5265,11 +5374,11 @@ defun_catch_4: {
try {
throw 42;
} catch (a) {
function a() {}
console.log(a);
}
}
expect_stdout: "42"
node_version: "<=4"
expect_stdout: true
}
defun_catch_5: {
@@ -5291,10 +5400,10 @@ defun_catch_5: {
throw 42;
} catch (a) {
console.log(a);
function a() {}
}
}
expect_stdout: "42"
node_version: "<=4"
expect_stdout: true
}
defun_catch_6: {
@@ -5481,7 +5590,7 @@ lvalues_def_1: {
}
expect: {
var b = 1;
var a = b++, b = NaN;
var a = +b, b = NaN;
console.log(a, b);
}
expect_stdout: "1 NaN"
@@ -7383,3 +7492,112 @@ issue_3974: {
}
expect_stdout: "PASS"
}
issue_4030: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
{
delete (a = "PASS");
A = "PASS";
}
console.log(A);
}
expect: {
A = "PASS";
console.log(A);
}
expect_stdout: "PASS"
}
global_assign: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
A = "FAIL";
this.A = "PASS";
console.log(A);
}
expect: {
A = "FAIL";
this.A = "PASS";
console.log(A);
}
expect_stdout: "PASS"
}
issue_4188_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
try {
while (A)
var a = function() {}, b = a;
} catch (a) {
console.log(function() {
return typeof a;
}(), typeof b);
}
})();
}
expect: {
(function() {
try {
while (A)
var a = function() {}, b = a;
} catch (a) {
console.log(function() {
return typeof a;
}(), typeof b);
}
})();
}
expect_stdout: "object undefined"
}
issue_4188_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
try {
throw 42;
} catch (a) {
console.log(function() {
return typeof a;
}(), typeof b);
}
while (!console)
var a = function() {}, b = a;
})();
}
expect: {
(function() {
try {
throw 42;
} catch (a) {
console.log(function() {
return typeof a;
}(), typeof b);
}
while (!console)
var a = function() {}, b = a;
})();
}
expect_stdout: "number undefined"
}

View File

@@ -80,3 +80,21 @@ log_global: {
}
expect_stdout: "[object global]"
}
issue_4054: {
input: {
console.log({
set p(v) {
throw "FAIL";
},
});
}
expect: {
console.log({
set p(v) {
throw "FAIL";
},
});
}
expect_stdout: "{ p: [Setter] }"
}

View File

@@ -877,7 +877,7 @@ for_init_var: {
expect_stdout: "PASS"
}
forin: {
forin_1: {
options = {
sequences: true,
}
@@ -895,6 +895,49 @@ forin: {
expect_stdout: "PASS"
}
forin_2: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var o = {
p: 1,
q: 2,
};
var k = "k";
for ((console.log("exp"), o)[function() {
console.log("prop");
return k;
}()] in function() {
console.log("obj");
return o;
}())
console.log(o.k, o[o.k]);
}
expect: {
var o = {
p: 1,
q: 2,
};
for ((console.log("exp"), o)[console.log("prop"), "k"] in console.log("obj"), o)
console.log(o.k, o[o.k]);
}
expect_stdout: [
"obj",
"exp",
"prop",
"p 1",
"exp",
"prop",
"q 2",
]
}
call: {
options = {
sequences: true,
@@ -1112,3 +1155,25 @@ issue_3703: {
}
expect_stdout: "PASS"
}
issue_4079: {
options = {
sequences: true,
side_effects: true,
}
input: {
try {
typeof (0, A);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
A;
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}

View File

@@ -245,6 +245,31 @@ unsafe_builtin_2: {
expect_stdout: "object PASS PASS"
}
unsafe_builtin_3: {
options = {
conditionals: true,
side_effects: true,
toplevel: true,
unsafe: true,
}
input: {
var o = {};
if (42 < Math.random())
o.p = "FAIL";
else
o.p = "PASS";
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {};
o.p = 42 < Math.random() ? "FAIL" : "PASS";
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: "p PASS"
}
unsafe_string_replace: {
options = {
side_effects: true,
@@ -298,7 +323,7 @@ operator_in: {
expect_stdout: "PASS"
}
issue_3983: {
issue_3983_1: {
options = {
collapse_vars: true,
conditionals: true,
@@ -323,7 +348,161 @@ issue_3983: {
}
expect: {
var a = "PASS";
g();
function g() {}
console.log(a);
}
expect_stdout: "PASS"
}
issue_3983_2: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
function f() {
g && g();
}
f();
function g() {
0 ? a : 0;
}
var b = a;
console.log(a);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4008: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = "PASS";
function f(b, b) {
console.log(b);
}
f && f(a && a[a]);
console.log(a);
}
expect: {
var a = "PASS";
function f(b, b) {
console.log(b);
}
f(a[a]);
console.log(a);
}
expect_stdout: [
"undefined",
"PASS",
]
}
trim_new: {
options = {
side_effects: true,
}
input: {
new function(a) {
console.log(a);
}("PASS");
}
expect: {
(function(a) {
console.log(a);
})("PASS");
}
expect_stdout: "PASS"
}
issue_4325: {
options = {
keep_fargs: "strict",
passes: 2,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function f() {
(function(b, c) {
try {
c.p = 0;
} catch (e) {
console.log("PASS");
return b;
}
c;
})(f++);
})();
}
expect: {
(function() {
(function() {
try {
(void 0).p = 0;
} catch (e) {
console.log("PASS");
return;
}
})();
})();
}
expect_stdout: "PASS"
}
issue_4366_1: {
options = {
side_effects: true,
}
input: {
({
p: 42,
get p() {},
q: console.log("PASS"),
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4366_2: {
options = {
side_effects: true,
}
input: {
({
set p(v) {},
q: console.log("PASS"),
p: 42,
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}

806
test/compress/spread.js Normal file
View File

@@ -0,0 +1,806 @@
collapse_vars_1: {
options = {
collapse_vars: true,
}
input: {
var a;
[ ...a = "PASS", "PASS"].slice();
console.log(a);
}
expect: {
var a;
[ ...a = "PASS", "PASS"].slice();
console.log(a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
collapse_vars_2: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
} catch (e) {
console.log(a);
}
}
expect: {
var a = "FAIL";
try {
a = "PASS";
[ ...42, "PASS"].slice();
} catch (e) {
console.log(a);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
collapse_vars_3: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
} catch (e) {
console.log(a);
}
}
expect: {
var a = "FAIL";
try {
[ ...(a = "PASS", 42), "PASS"].slice();
} catch (e) {
console.log(a);
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
collapse_vars_4: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a) {
return a;
}(...[ "PASS", "FAIL" ]));
}
expect: {
console.log(function(a) {
return a;
}(...[ "PASS", "FAIL" ]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
dont_inline: {
options = {
inline: true,
}
input: {
console.log(function(a) {
return a;
}(...[ "PASS", "FAIL" ]));
}
expect: {
console.log(function(a) {
return a;
}(...[ "PASS", "FAIL" ]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
do_inline: {
options = {
inline: true,
spread: true,
}
input: {
console.log(function(a) {
return a;
}(...[ "PASS", "FAIL" ]));
}
expect: {
console.log(("FAIL", "PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
drop_empty_call_1: {
options = {
side_effects: true,
}
input: {
try {
(function() {})(...null);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
[ ...null ];
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
drop_empty_call_2: {
options = {
side_effects: true,
spread: true,
}
input: {
(function() {})(...[ console.log("PASS") ]);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=6"
}
convert_hole: {
options = {
spread: true,
}
input: {
console.log(...[ "PASS", , 42 ]);
}
expect: {
console.log("PASS", void 0, 42);
}
expect_stdout: "PASS undefined 42"
node_version: ">=6"
}
keep_property_access: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log(function() {
return [ ..."foo" ][0];
}());
}
expect: {
console.log(function() {
return [ ..."foo" ][0];
}());
}
expect_stdout: "f"
node_version: ">=6"
}
keep_fargs: {
options = {
keep_fargs: "strict",
unused: true,
}
input: {
var a = [ "PASS" ];
(function(b, c) {
console.log(c);
})(console, ...a);
}
expect: {
var a = [ "PASS" ];
(function(b, c) {
console.log(c);
})(console, ...a);
}
expect_stdout: "PASS"
node_version: ">=6"
}
reduce_vars_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function(b, c) {
return c ? "PASS" : "FAIL";
}(..."foo"));
}
expect: {
console.log(function(b, c) {
return c ? "PASS" : "FAIL";
}(..."foo"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
reduce_vars_2: {
options = {
conditionals: true,
evaluate: true,
reduce_vars: true,
}
input: {
console.log(function(b, c) {
return c ? "PASS" : "FAIL";
}(..."foo"));
}
expect: {
console.log(function(b, c) {
return c ? "PASS" : "FAIL";
}(..."foo"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
convert_setter: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
...{
set PASS(v) {},
},
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
PASS: void 0,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: "PASS undefined"
node_version: ">=8"
}
keep_getter_1: {
options = {
side_effects: true,
}
input: {
({
...{
get p() {
console.log("PASS");
},
},
get q() {
console.log("FAIL");
},
});
}
expect: {
({
...{
get p() {
console.log("PASS");
},
},
});
}
expect_stdout: "PASS"
node_version: ">=8"
}
keep_getter_2: {
options = {
side_effects: true,
}
input: {
({
...(console.log("foo"), {
get p() {
console.log("bar");
},
}),
});
}
expect: {
({
...(console.log("foo"), {
get p() {
console.log("bar");
},
}),
});
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=8"
}
keep_getter_3: {
options = {
side_effects: true,
}
input: {
({
...function() {
return {
get p() {
console.log("PASS");
},
};
}(),
});
}
expect: {
({
...function() {
return {
get p() {
console.log("PASS");
},
};
}(),
});
}
expect_stdout: "PASS"
node_version: ">=8"
}
keep_getter_4: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var o = {
get p() {
console.log("PASS");
},
};
({
q: o,
...o,
});
}
expect: {
var o = {
get p() {
console.log("PASS");
},
};
({
...o,
});
}
expect_stdout: "PASS"
node_version: ">=8"
}
keep_accessor: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
...{
get p() {
console.log("GET");
return this.r;
},
set q(v) {
console.log("SET", v);
},
r: 42,
},
r: null,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
...{
get p() {
console.log("GET");
return this.r;
},
set q(v) {
console.log("SET", v);
},
r: 42,
},
r: null,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"GET",
"p 42",
"q undefined",
"r null",
]
node_version: ">=8"
}
object_key_order_1: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
...{},
a: 1,
b: 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: (1, 3),
b: 2,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
node_version: ">=8 <=10"
}
object_key_order_2: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
a: 1,
...{},
b: 2,
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: (1, 3),
b: 2,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
node_version: ">=8"
}
object_key_order_3: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
a: 1,
b: 2,
...{},
a: 3,
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: (1, 3),
b: 2,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
node_version: ">=8"
}
object_key_order_4: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
a: 1,
b: 2,
a: 3,
...{},
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
a: (1, 3),
b: 2,
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"a 3",
"b 2",
]
node_version: ">=8"
}
object_spread_array: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
...[ "foo", "bar" ],
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
...[ "foo", "bar" ],
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"0 foo",
"1 bar",
]
node_version: ">=8"
}
object_spread_string: {
options = {
objects: true,
spread: true,
}
input: {
var o = {
..."foo",
};
for (var k in o)
console.log(k, o[k]);
}
expect: {
var o = {
..."foo",
};
for (var k in o)
console.log(k, o[k]);
}
expect_stdout: [
"0 f",
"1 o",
"2 o",
]
node_version: ">=8"
}
unused_var_side_effects: {
options = {
unused: true,
}
input: {
(function f(a) {
var b = {
...a,
};
})({
get p() {
console.log("PASS");
},
});
}
expect: {
(function(a) {
({
...a,
});
})({
get p() {
console.log("PASS");
},
});
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4329: {
options = {
objects: true,
spread: true,
}
input: {
console.log({
...{
get 0() {
return "FAIL";
},
...{
0: "PASS",
},
},
}[0]);
}
expect: {
console.log({
...{
get 0() {
return "FAIL";
},
[0]: "PASS",
},
}[0]);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4331: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var a = "PASS", b;
console,
b = a;
(function() {
a++;
})(...a);
console.log(b);
}
expect: {
var a = "PASS", b;
console;
(function() {
a++;
})(...b = a);
console.log(b);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4342: {
options = {
side_effects: true,
}
input: {
try {
new function() {}(...42);
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
[ ...42 ];
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4345: {
options = {
objects: true,
spread: true,
}
input: {
console.log({
...{
get 42() {
return "FAIL";
},
...{},
42: "PASS",
},
}[42]);
}
expect: {
console.log({
...{
get 42() {
return "FAIL";
},
[42]: "PASS",
},
}[42]);
}
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4361: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
var a = console.log("foo");
console;
var b = {
...a,
};
}());
}
expect: {
console.log(function() {
var a = console.log("foo");
console;
({
...a,
});
}());
}
expect_stdout: [
"foo",
"undefined",
]
node_version: ">=8"
}
issue_4363: {
options = {
objects: true,
spread: true,
}
input: {
({
...{
set [console.log("PASS")](v) {},
},
});
}
expect: {
({
[console.log("PASS")]: void 0,
});
}
expect_stdout: "PASS"
node_version: ">=8"
}

View File

@@ -1,5 +1,6 @@
constant_switch_1: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -19,6 +20,7 @@ constant_switch_1: {
constant_switch_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -39,6 +41,7 @@ constant_switch_2: {
constant_switch_3: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -60,6 +63,7 @@ constant_switch_3: {
constant_switch_4: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -86,6 +90,7 @@ constant_switch_4: {
constant_switch_5: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -120,6 +125,7 @@ constant_switch_5: {
constant_switch_6: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -154,6 +160,7 @@ constant_switch_6: {
constant_switch_7: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -197,6 +204,7 @@ constant_switch_7: {
constant_switch_8: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -226,6 +234,7 @@ constant_switch_8: {
constant_switch_9: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -315,6 +324,7 @@ keep_default: {
issue_1663: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -551,6 +561,7 @@ issue_441_2: {
issue_1674: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
@@ -876,6 +887,7 @@ beautify: {
issue_1758: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
@@ -898,15 +910,16 @@ issue_1758: {
issue_2535: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch(w(), 42) {
case 13: x();
case 42: y();
default: z();
case 13: x();
case 42: y();
default: z();
}
}
expect: {
@@ -919,6 +932,7 @@ issue_2535: {
issue_1750: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
switches: true,
@@ -963,6 +977,7 @@ drop_switch_1: {
drop_switch_2: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
@@ -1007,6 +1022,7 @@ drop_switch_3: {
drop_switch_4: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
@@ -1028,3 +1044,140 @@ drop_switch_4: {
}
expect_stdout: "PASS"
}
drop_switch_5: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
input: {
switch (A) {
case B:
x();
default:
}
switch (C) {
default:
y();
case D:
}
}
expect: {
A === B && x();
C !== D && y();
}
}
drop_switch_6: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
input: {
switch (A) {
case B:
default:
x();
}
switch (C) {
default:
case D:
y();
}
}
expect: {
A === B;
x();
C !== D;
y();
}
}
drop_switch_7: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
input: {
switch (A) {
case B:
w();
default:
x();
}
switch (C) {
default:
y();
case D:
z();
}
}
expect: {
A === B && w();
x();
C !== D && y();
z();
}
}
drop_switch_8: {
options = {
conditionals: true,
dead_code: true,
switches: true,
}
input: {
switch (A) {
case B:
w();
break;
default:
x();
}
switch (C) {
default:
y();
break;
case D:
z();
}
}
expect: {
(A === B ? w : x)();
(C !== D ? y : z)();
}
}
issue_4059: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (0) {
default:
case 1:
break;
case a:
break;
var a;
}
console.log("PASS");
}
expect: {
switch (0) {
default:
break;
case a:
break;
var a;
}
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -1,3 +1,37 @@
ascii_only_false: {
options = {}
beautify = {
ascii_only: false,
}
input: {
console.log(
"\x000\x001\x007\x008\x00",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
);
}
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f","\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\');'
expect_stdout: true
}
ascii_only_true: {
options = {}
beautify = {
ascii_only: true,
}
input: {
console.log(
"\x000\x001\x007\x008\x00",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
);
}
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f","\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f",\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\');'
expect_stdout: true
}
unicode_parse_variables: {
options = {}
input: {
@@ -141,3 +175,35 @@ issue_2569: {
}
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
}
surrogate_pair: {
beautify = {
ascii_only: false,
}
input: {
var \u{2f800} = {
\u{2f801}: "\u{100000}",
};
\u{2f800}.\u{2f802} = "\u{100001}";
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
}
expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);'
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
node_version: ">=4"
}
surrogate_pair_ascii: {
beautify = {
ascii_only: true,
}
input: {
var \u{2f800} = {
\u{2f801}: "\u{100000}",
};
\u{2f800}.\u{2f802} = "\u{100001}";
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
}
expect_exact: 'var \\u{2f800}={"\\ud87e\\udc01":"\\udbc0\\udc00"};\\u{2f800}.\\u{2f802}="\\udbc0\\udc01";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\ud87e\\udc02"]);'
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
node_version: ">=4"
}

411
test/compress/varify.js Normal file
View File

@@ -0,0 +1,411 @@
reduce_merge_const: {
options = {
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
const a = console;
console.log(typeof a);
var b = typeof a;
console.log(b);
}
expect: {
var b = console;
console.log(typeof b);
b = typeof b;
console.log(b);
}
expect_stdout: [
"object",
"object",
]
}
reduce_merge_let: {
options = {
merge_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
"use strict";
let a = console;
console.log(typeof a);
var b = typeof a;
console.log(b);
}
expect: {
"use strict";
var b = console;
console.log(typeof b);
b = typeof b;
console.log(b);
}
expect_stdout: [
"object",
"object",
]
node_version: ">=4"
}
reduce_block_const: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
{
const a = typeof console;
console.log(a);
}
}
expect: {
var a = typeof console;
console.log(a);
}
expect_stdout: "object"
}
reduce_block_let: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
{
let a = typeof console;
console.log(a);
}
}
expect: {
"use strict";
var a = typeof console;
console.log(a);
}
expect_stdout: "object"
node_version: ">=4"
}
hoist_props_const: {
options = {
hoist_props: true,
passes: 2,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
{
const o = {
p: "PASS",
};
console.log(o.p);
}
}
expect: {
var o_p = "PASS";
console.log(o_p);
}
expect_stdout: "PASS"
}
hoist_props_let: {
options = {
hoist_props: true,
passes: 2,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
{
let o = {
p: "PASS",
};
console.log(o.p);
}
}
expect: {
"use strict";
var o_p = "PASS";
console.log(o_p);
}
expect_stdout: "PASS"
node_version: ">=4"
}
scope_adjustment_const: {
options = {
conditionals: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
for (var k in [ 42 ])
console.log(function f() {
if (k) {
const a = 0;
}
}());
}
expect: {
for (var k in [ 42 ])
console.log(void (k && 0));
}
expect_stdout: "undefined"
}
scope_adjustment_let: {
options = {
conditionals: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
"use strict";
for (var k in [ 42 ])
console.log(function f() {
if (k) {
let a = 0;
}
}());
}
expect: {
"use strict";
for (var k in [ 42 ])
console.log(void (k && 0));
}
expect_stdout: "undefined"
node_version: ">=4"
}
issue_4191_const: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
const a = function() {};
console.log(typeof a, a());
}
expect: {
function a() {};
console.log(typeof a, a());
}
expect_stdout: "function undefined"
}
issue_4191_let: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
"use strict";
let a = function() {};
console.log(typeof a, a());
}
expect: {
"use strict";
function a() {};
console.log(typeof a, a());
}
expect_stdout: "function undefined"
node_version: ">=4"
}
forin_const_1: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
const o = {
foo: 42,
bar: "PASS",
};
for (const k in o)
console.log(k, o[k]);
}
expect: {
var o = {
foo: 42,
bar: "PASS",
};
for (const k in o)
console.log(k, o[k]);
}
expect_stdout: true
node_version: ">=4"
}
forin_const_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
const o = {
p: 42,
q: "PASS",
};
for (const [ k ] in o)
console.log(k, o[k]);
}
expect: {
var o = {
p: 42,
q: "PASS",
}, k;
for ([ k ] in o)
console.log(k, o[k]);
}
expect_stdout: [
"p 42",
"q PASS",
]
node_version: ">=6"
}
forin_let_1: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
let o = {
foo: 42,
bar: "PASS",
};
for (let k in o)
console.log(k, o[k]);
}
expect: {
"use strict";
var o = {
foo: 42,
bar: "PASS",
}, k;
for (k in o)
console.log(k, o[k]);
}
expect_stdout: [
"foo 42",
"bar PASS",
]
node_version: ">=4"
}
forin_let_2: {
options = {
join_vars: true,
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
let o = {
p: 42,
q: "PASS",
};
for (let [ k ] in o)
console.log(k, o[k]);
}
expect: {
var o = {
p: 42,
q: "PASS",
}, k;
for ([ k ] in o)
console.log(k, o[k]);
}
expect_stdout: [
"p 42",
"q PASS",
]
node_version: ">=6"
}
issue_4290_1_const: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
const a = 0;
var a;
}
expect: {
const a = 0;
var a;
}
expect_stdout: true
}
issue_4290_1_let: {
options = {
reduce_vars: true,
toplevel: true,
varify: true,
}
input: {
"use strict";
let a = 0;
var a;
}
expect: {
"use strict";
let a = 0;
var a;
}
expect_stdout: true
node_version: ">=4"
}
drop_forin_let: {
options = {
loops: true,
toplevel: true,
unused: true,
varify: true,
}
input: {
"use strict";
for (let a in console.log("PASS"));
}
expect: {
"use strict";
console.log("PASS");
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -0,0 +1,8 @@
function f() {
var { eval } = null;
}
function g() {
"use strict";
var { eval } = 42;
}

View File

@@ -0,0 +1,4 @@
switch (0) {
default:
default:
}

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
try {
"foo" in 42;
} catch ({
message,
}) {
console.log(message);
}

View File

@@ -0,0 +1,15 @@
// (beautified)
try {
1 in 0;
} catch ({
message: message
}) {
console.log(message);
}
// output: Cannot use 'in' operator to search for '1' in 0
//
// minify: Cannot use 'in' operator to search for '0' in 0
//
// options: {
// "mangle": false
// }

View File

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

View File

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

View File

@@ -60,7 +60,7 @@ if (typeof phantom == "undefined") {
var port = server.address().port;
if (debug) {
console.log("http://localhost:" + port + "/");
} else {
} else (function install() {
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
"install",
"phantomjs-prebuilt@2.1.14",
@@ -71,7 +71,10 @@ if (typeof phantom == "undefined") {
], {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
if (code) throw new Error("npm install failed!");
if (code) {
console.log("npm install failed with code", code);
return install();
}
var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
program.stdout.pipe(process.stdout);
program.stderr.pipe(process.stderr);
@@ -82,7 +85,7 @@ if (typeof phantom == "undefined") {
process.exit(0);
});
});
}
})();
});
server.timeout = 0;
} else {

65
test/mocha/async.js Normal file
View File

@@ -0,0 +1,65 @@
var assert = require("assert");
var UglifyJS = require("../node");
describe("async", function() {
it("Should reject `await` as symbol name within async functions only", function() {
[
"function await() {}",
"function(await) {}",
"function() { await; }",
"function() { await:{} }",
"function() { var await; }",
"function() { function await() {} }",
"function() { try {} catch (await) {} }",
].forEach(function(code) {
var ast = UglifyJS.parse("(" + code + ")();");
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 1);
assert.strictEqual(ast.body[0].TYPE, "SimpleStatement");
assert.strictEqual(ast.body[0].body.TYPE, "Call");
assert.strictEqual(ast.body[0].body.expression.TYPE, "Function");
assert.throws(function() {
UglifyJS.parse("(async " + code + ")();");
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
it("Should reject `await` expression outside of async functions", function() {
[
"await 42;",
"function f() { await 42; }",
"async function f() { function g() { await 42; } }",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
it("Should reject `await` expression directly on computed key of function argument", function() {
[
"function f({ [await 42]: a }) {}",
"async function f({ [await 42]: a }) {}",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
it("Should accept `await` expression nested within computed key of function argument", function() {
[
"function f({ [async function() { await 42; }()]: a }) {}",
"async function f({ [async function() { await 42; }()]: a }) {}",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 1);
assert.strictEqual(ast.body[0].argnames.length, 1);
assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject");
});
});
});

View File

@@ -330,7 +330,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should fail with invalid syntax", function(done) {
var command = uglifyjscmd + ' test/input/invalid/simple.js';
var command = uglifyjscmd + " test/input/invalid/simple.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
@@ -342,7 +342,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should fail with correct marking of tabs", function(done) {
var command = uglifyjscmd + ' test/input/invalid/tab.js';
var command = uglifyjscmd + " test/input/invalid/tab.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
@@ -354,7 +354,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should fail with correct marking at start of line", function(done) {
var command = uglifyjscmd + ' test/input/invalid/eof.js';
var command = uglifyjscmd + " test/input/invalid/eof.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
@@ -366,7 +366,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should fail with a missing loop body", function(done) {
var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js';
var command = uglifyjscmd + " test/input/invalid/loop-no-body.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
@@ -378,7 +378,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (5--)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
var command = uglifyjscmd + " test/input/invalid/assign_1.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -392,7 +392,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (Math.random() /= 2)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
var command = uglifyjscmd + " test/input/invalid/assign_2.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -406,7 +406,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (++this)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
var command = uglifyjscmd + " test/input/invalid/assign_3.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -420,7 +420,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (++null)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
var command = uglifyjscmd + " test/input/invalid/assign_4.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -434,7 +434,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (a.=)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
var command = uglifyjscmd + " test/input/invalid/dot_1.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -448,7 +448,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (%.a)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
var command = uglifyjscmd + " test/input/invalid/dot_2.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -462,7 +462,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (a./();)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
var command = uglifyjscmd + " test/input/invalid/dot_3.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -476,7 +476,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error ({%: 1})", function(done) {
var command = uglifyjscmd + ' test/input/invalid/object.js';
var command = uglifyjscmd + " test/input/invalid/object.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -490,7 +490,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (delete x)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/delete.js';
var command = uglifyjscmd + " test/input/invalid/delete.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -504,7 +504,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (function g(arguments))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
var command = uglifyjscmd + " test/input/invalid/function_1.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -518,7 +518,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (function eval())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
var command = uglifyjscmd + " test/input/invalid/function_2.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -532,7 +532,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (iife arguments())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
var command = uglifyjscmd + " test/input/invalid/function_3.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -546,7 +546,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (catch (eval))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/try.js';
var command = uglifyjscmd + " test/input/invalid/try.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -560,7 +560,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (var eval)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/var.js';
var command = uglifyjscmd + " test/input/invalid/var.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -573,8 +573,22 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should throw syntax error (var { eval })", function(done) {
var command = uglifyjscmd + " test/input/invalid/destructured_var.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/destructured_var.js:7,10",
" var { eval } = 42;",
" ^",
"ERROR: Unexpected eval in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (else)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/else.js';
var command = uglifyjscmd + " test/input/invalid/else.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -588,7 +602,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (return)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/return.js';
var command = uglifyjscmd + " test/input/invalid/return.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -602,7 +616,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (for-in init)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
var command = uglifyjscmd + " test/input/invalid/for-in_1.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -616,7 +630,7 @@ describe("bin/uglifyjs", function() {
});
});
it("Should throw syntax error (for-in var)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
var command = uglifyjscmd + " test/input/invalid/for-in_2.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
@@ -629,6 +643,18 @@ describe("bin/uglifyjs", function() {
done();
});
});
it("Should throw syntax error (switch defaults)", function(done) {
var command = uglifyjscmd + " test/input/invalid/switch.js";
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/switch.js:3,2");
assert.strictEqual(lines[1], " default:");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "ERROR: More than one default clause in switch statement");
done();
});
});
it("Should handle literal string as source map input", function(done) {
var command = [
uglifyjscmd,

View File

@@ -28,4 +28,65 @@ describe("Number literals", function() {
assert.throws(test(inputs[i]), error, inputs[i]);
}
});
it("Should parse binary, hexadecimal, octal and underscore correctly", function() {
[
"42",
"4_2",
"052",
"0o52",
"0O52",
"0o5_2",
"0x2a",
"0X2A",
"0x2_a",
"0b101010",
"0B101010",
"0b101_010",
"0.0000000042e+10",
"0.0000000042E+10",
"0.0_000000042e+10",
"0.0000000042e+1_0",
"0.000_000_004_2e+1_0",
"0.000_000_004_2e+1_0-0B101_010+0x2_A-0o5_2+4_2",
].forEach(function(code) {
var result = UglifyJS.minify(code, {
compress: {
expression: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "42;");
});
});
it("Should reject invalid use of underscore", function() {
[
"_42",
"_+42",
"+_42",
].forEach(function(code) {
var node = UglifyJS.parse(code, {
expression: true,
});
assert.ok(!node.is_constant(), code);
assert.ok(!(node instanceof UglifyJS.AST_Statement), code);
});
[
"42_",
"4__2",
"0_52",
"05_2",
"0_o52",
"0o_52",
"0.0000000042_e10",
"0.0000000042e_10",
"0.0000000042e_+10",
"0.0000000042e+_10",
].forEach(function(code) {
assert.throws(function() {
UglifyJS.parse(code);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
}, code);
});
});
});

View File

@@ -24,6 +24,9 @@ describe("test/reduce.js", function() {
});
it("Should eliminate unreferenced labels", function() {
var result = reduce_test(read("test/input/reduce/label.js"), {
compress: {
unsafe_math: true,
},
mangle: false,
}, {
verbose: false,
@@ -310,4 +313,12 @@ describe("test/reduce.js", function() {
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
});
it("Should handle destructured catch expressions", function() {
if (semver.satisfies(process.version, "<6")) return;
var result = reduce_test(read("test/input/reduce/destructured_catch.js"), {
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/destructured_catch.reduced.js"));
});
});

View File

@@ -1,64 +1,58 @@
var assert = require("assert");
var run_code = require("../sandbox").run_code;
var UglifyJS = require("../node");
describe("String literals", function() {
it("Should throw syntax error if a string literal contains a newline", function() {
var inputs = [
[
"'\n'",
"'\r'",
'"\r\n"',
"'\u2028'",
'"\u2029"'
];
var test = function(input) {
return function() {
'"\u2029"',
].forEach(function(input) {
assert.throws(function() {
var ast = UglifyJS.parse(input);
};
};
var error = function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unterminated string constant";
};
for (var input in inputs) {
assert.throws(test(inputs[input]), error);
}
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unterminated string constant";
});
});
});
it("Should handle line continuation correctly", function() {
[
'"\\\r"',
'"\\\n"',
'"\\\r\n"',
].forEach(function(str) {
var code = "console.log(" + str + ");";
var result = UglifyJS.minify(code);
if (result.error) throw result.error;
assert.strictEqual(run_code(result.code), run_code(code));
});
});
it("Should not throw syntax error if a string has a line continuation", function() {
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
assert.equal(output, 'var a="ab";');
var ast = UglifyJS.parse('var a = "a\\\nb";');
assert.equal(ast.print_to_string(), 'var a="ab";');
});
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
var inputs = [
[
'"use strict";\n"\\76";',
'"use strict";\nvar foo = "\\76";',
'"use strict";\n"\\1";',
'"use strict";\n"\\07";',
'"use strict";\n"\\011"'
];
var test = function(input) {
return function() {
'"use strict";\n"\\011"',
].forEach(function(input) {
assert.throws(function() {
var output = UglifyJS.parse(input);
}
};
var error = function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
}
for (var input in inputs) {
assert.throws(test(inputs[input]), error);
}
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
});
});
});
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
var tests = [
[
[ ';"\\76";', ';">";' ],
[ ';"\\0";', ';"\\0";' ],
[ ';"\\08"', ';"\\x008";' ],
@@ -66,19 +60,15 @@ describe("String literals", function() {
[ ';"\\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) {
var output = UglifyJS.parse(tests[test][0]).print_to_string();
assert.equal(output, tests[test][1]);
}
].forEach(function(test) {
var ast = UglifyJS.parse(test[0]);
assert.equal(ast.print_to_string(), test[1]);
});
});
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";');
});
it("Should not unescape unpaired surrogates", function() {
var code = [];
for (var i = 0; i <= 0xF; i++) {
@@ -115,4 +105,33 @@ describe("String literals", function() {
assert.ok(code.length > ascii.code.length);
assert.strictEqual(eval(code), eval(ascii.code));
});
it("Should reject invalid Unicode escape sequence", function() {
[
'var foo = "\\u-111"',
'var bar = "\\u{-1}"',
'var baz = "\\ugggg"',
].forEach(function(test) {
assert.throws(function() {
UglifyJS.parse(test);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Invalid hex-character pattern in string";
});
});
});
it("Should reject invalid code points in Unicode escape sequence", function() {
[
// A bit over the valid range
'"\\u{110000}"',
// 32-bit overflow resulting in "a"
'"\\u{100000061}"',
].forEach(function(test) {
assert.throws(function() {
UglifyJS.parse(test);
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& /^Invalid character code: /.test(e.message);
});
});
});
});

View File

@@ -5,7 +5,7 @@ describe("tokens", function() {
it("Should give correct positions for accessors", function() {
// location 0 1 2 3 4
// 01234567890123456789012345678901234567890123456789
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
// test all AST_ObjectProperty tokens are set as expected
var found = false;
ast.walk(new UglifyJS.TreeWalker(function(node) {
@@ -13,9 +13,9 @@ describe("tokens", function() {
found = true;
assert.equal(node.start.pos, 12);
assert.equal(node.end.endpos, 46);
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
assert.equal(node.key.start.pos, 16);
assert.equal(node.key.end.endpos, 22);
assert(node.key instanceof UglifyJS.AST_SymbolRef);
assert.equal(node.key.start.pos, 17);
assert.equal(node.key.end.endpos, 21);
assert(node.value instanceof UglifyJS.AST_Accessor);
assert.equal(node.value.start.pos, 22);
assert.equal(node.value.end.endpos, 46);

View File

@@ -17,7 +17,7 @@ describe("With", function() {
var ast = UglifyJS.parse("with(e) {f(1, 2)}");
ast.figure_out_scope();
assert.equal(ast.uses_with, true);
assert.equal(ast.body[0].expression.scope.uses_with, true);
assert.equal(ast.body[0].body.body[0].body.expression.scope.uses_with, true);
assert.equal(ast.body[0].expression.scope.resolve().uses_with, true);
assert.equal(ast.body[0].body.body[0].body.expression.scope.resolve().uses_with, true);
});
});

View File

@@ -18,9 +18,18 @@ var sandbox = require("./sandbox");
Error.stackTraceLimit = Infinity;
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 print_options = {};
[
"ie8",
"v8",
"webkit",
].forEach(function(name) {
var value = minify_options[name] || minify_options.output && minify_options.output[name];
if (value) print_options[name] = value;
});
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string(print_options);
var max_iterations = reduce_options.max_iterations || 1000;
var max_timeout = reduce_options.max_timeout || 10000;
var warnings = [];
@@ -95,6 +104,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
// quick ignores
if (node instanceof U.AST_Accessor) return;
if (node instanceof U.AST_Destructured) return;
if (node instanceof U.AST_Directive) return;
if (!in_list && node instanceof U.AST_EmptyStatement) return;
if (node instanceof U.AST_Label) return;
@@ -112,19 +122,20 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
// 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
// ignore lvalues
if (parent instanceof U.AST_Assign && parent.left === node) return;
if (parent instanceof U.AST_DestructuredArray) return;
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
case "++":
case "--":
case "delete":
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;
}
// preserve for (var xxx; ...)
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
// preserve for (xxx in ...)
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
// node specific permutations with no parent logic
@@ -133,7 +144,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
if (expr && !(expr instanceof U.AST_Hole)) {
node.start._permute++;
CHANGED = true;
return expr;
return expr instanceof U.AST_Spread ? expr.expression : expr;
}
}
else if (node instanceof U.AST_Binary) {
@@ -146,7 +157,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return permute < 2 ? expr : wrap_with_console_log(expr);
}
else if (node instanceof U.AST_BlockStatement) {
if (in_list) {
if (in_list && node.body.filter(function(node) {
return node instanceof U.AST_Const;
}).length == 0) {
node.start._permute++;
CHANGED = true;
return List.splice(node.body);
@@ -160,7 +173,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
][ ((node.start._permute += step) * steps | 0) % 3 ];
if (expr) {
CHANGED = true;
return expr;
return expr instanceof U.AST_Spread ? expr.expression : expr;
}
if (node.expression instanceof U.AST_Arrow && node.expression.value) {
var seq = node.args.slice();
seq.push(node.expression.value);
CHANGED = true;
return to_sequence(seq);
}
if (node.expression instanceof U.AST_Function) {
// hoist and return expressions from the IIFE function expression
@@ -249,13 +268,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
}
else if (node instanceof U.AST_ForIn) {
var expr = [
node.init,
node.object,
node.body,
][ (node.start._permute * steps | 0) % 3 ];
var expr;
switch ((node.start._permute * steps | 0) % 3) {
case 0:
if (!(node.init instanceof U.AST_Definitions
&& node.init.definitions[0].name instanceof U.AST_Destructured)) {
expr = node.init;
}
break;
case 1:
expr = node.object;
break;
case 2:
if (!has_loopcontrol(node.body, node, parent)) expr = node.body;
break;
}
node.start._permute += step;
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
if (expr) {
CHANGED = true;
return to_statement(expr);
}
@@ -367,9 +396,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
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) {
// drop switch branches
if (parent instanceof U.AST_Switch && parent.expression != node) {
node.start._permute++;
CHANGED = true;
return List.skip;
@@ -388,6 +416,15 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
CHANGED = true;
return List.skip;
}
// skip element/property from (destructured) array/object
if (parent instanceof U.AST_Array
|| parent instanceof U.AST_Destructured
|| parent instanceof U.AST_Object) {
node.start._permute++;
CHANGED = true;
return List.skip;
}
}
// replace this node
@@ -411,7 +448,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
start: {},
});
}
else if (node instanceof U.AST_Var) {
else if (node instanceof U.AST_Definitions) {
// remove empty var statement
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
start: {},
@@ -428,7 +465,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
return to_sequence(node.args);
}
if (node instanceof U.AST_Catch) {
if (node instanceof U.AST_Catch && node.argname instanceof U.AST_SymbolCatch) {
descend(node, this);
node.body.unshift(new U.AST_SimpleStatement({
body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
@@ -437,7 +474,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
return node;
}
}));
var code = testcase_ast.print_to_string();
var code = testcase_ast.print_to_string(print_options);
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
if (diff && !diff.timed_out && !diff.error) {
testcase = code;
@@ -452,6 +489,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
node.start = JSON.parse(JSON.stringify(node.start));
node.start._permute = 0;
}));
var before_iterations = testcase;
for (var c = 0; c < max_iterations; ++c) {
if (verbose && pass == 1 && c % 25 == 0) {
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
@@ -460,7 +498,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
var code_ast = testcase_ast.clone(true).transform(tt);
if (!CHANGED) break;
try {
var code = code_ast.print_to_string();
var code = code_ast.print_to_string(print_options);
} catch (ex) {
// AST is not well formed.
// no harm done - just log the error, ignore latest change and continue iterating.
@@ -494,12 +532,33 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
}
}
if (c == 0) break;
if (before_iterations === testcase) break;
if (verbose) {
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
}
}
testcase = try_beautify(testcase, minify_options, differs.unminified_result, result_cache, max_timeout);
var beautified = U.minify(testcase, {
compress: false,
mangle: false,
output: function() {
var options = JSON.parse(JSON.stringify(print_options));
options.beautify = true;
options.braces = true;
options.comments = true;
return options;
}(),
});
testcase = {
code: testcase,
};
if (!beautified.error) {
diff = test_for_diff(beautified.code, minify_options, result_cache, max_timeout);
if (diff && !diff.timed_out && !diff.error) {
testcase = beautified;
testcase.code = "// (beautified)\n" + testcase.code;
differs = diff;
}
}
var lines = [ "" ];
if (isNaN(max_timeout)) {
lines.push("// minify error: " + to_comment(strip_color_codes(differs.minified_result.stack)));
@@ -538,34 +597,6 @@ function trim_trailing_whitespace(value) {
return ("" + value).replace(/\s+$/, "");
}
function try_beautify(testcase, minify_options, expected, result_cache, 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);
if (isNaN(timeout)) {
if (!U.minify(result.code, minify_options).error) return {
code: testcase,
};
} else {
var actual = run_code(result.code, toplevel, result_cache, 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) {
@@ -600,11 +631,12 @@ function is_error(result) {
}
function is_timed_out(result) {
return is_error(result) && /timed out/.test(result);
return is_error(result) && /timed out/.test(result.message);
}
function is_statement(node) {
return node instanceof U.AST_Statement && !(node instanceof U.AST_Function);
return node instanceof U.AST_Statement
&& !(node instanceof U.AST_Arrow || node instanceof U.AST_AsyncFunction || node instanceof U.AST_Function);
}
function merge_sequence(array, node) {
@@ -650,7 +682,15 @@ function wrap_with_console_log(node) {
function run_code(code, toplevel, result_cache, timeout) {
var key = crypto.createHash("sha1").update(code).digest("base64");
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
var value = result_cache[key];
if (!value) {
var start = Date.now();
result_cache[key] = value = {
result: sandbox.run_code(code, toplevel, timeout),
elapsed: Date.now() - start,
};
}
return value;
}
function compare_run_code(code, minify_options, result_cache, max_timeout) {
@@ -658,21 +698,19 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
if (minified.error) return minified;
var toplevel = sandbox.has_toplevel(minify_options);
var elapsed = Date.now();
var unminified_result = run_code(code, toplevel, result_cache, max_timeout);
elapsed = Date.now() - elapsed;
var timeout = Math.min(100 * elapsed, max_timeout);
var minified_result = run_code(minified.code, toplevel, result_cache, timeout);
var unminified = run_code(code, toplevel, result_cache, max_timeout);
var timeout = Math.min(100 * unminified.elapsed, max_timeout);
var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result;
if (sandbox.same_stdout(unminified_result, minified_result)) {
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
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,
unminified_result: unminified.result,
minified_result: minified_result,
elapsed: elapsed,
elapsed: unminified.elapsed,
};
}

View File

@@ -26,21 +26,31 @@ var setupContext = new vm.Script([
]).join("\n"));
function createContext() {
var ctx = vm.createContext(Object.defineProperty({}, "console", { value: { log: log } }));
var ctx = vm.createContext(Object.defineProperties({}, {
console: { value: { log: log } },
global: { get: self },
self: { get: self },
window: { get: self },
}));
var global = setupContext.runInContext(ctx);
return ctx;
function self() {
return this;
}
function safe_log(arg, level) {
if (arg) switch (typeof arg) {
case "function":
case "function":
return arg.toString();
case "object":
case "object":
if (arg === global) return "[object global]";
if (/Error$/.test(arg.name)) return arg.toString();
if (typeof arg.then == "function") return "[object Promise]";
arg.constructor.toString();
if (level--) for (var key in arg) {
var desc = Object.getOwnPropertyDescriptor(arg, key);
if (!desc || !desc.get) arg[key] = safe_log(arg[key], level);
if (!desc || !desc.get && !desc.set) arg[key] = safe_log(arg[key], level);
}
}
return arg;

67
test/ufuzz/actions.js Normal file
View File

@@ -0,0 +1,67 @@
var get = require("https").get;
var parse = require("url").parse;
var base, token, run_number, eldest = true;
exports.init = function(url, auth, num) {
base = url;
token = auth;
run_number = num;
};
exports.should_stop = function(callback) {
read(base + "/actions/runs?per_page=100", function(reply) {
if (!reply || !Array.isArray(reply.workflow_runs)) return;
var runs = reply.workflow_runs.filter(function(workflow) {
return workflow.status != "completed";
}).sort(function(a, b) {
return b.run_number - a.run_number;
});
var found = false, remaining = 20;
(function next() {
if (!runs.length) return;
var workflow = runs.pop();
if (workflow.event == "schedule" && workflow.run_number == run_number) found = true;
read(workflow.jobs_url, function(reply) {
if (!reply || !Array.isArray(reply.jobs)) return;
if (!reply.jobs.every(function(job) {
if (job.status == "completed") return true;
remaining--;
return found || workflow.event != "schedule";
})) return;
if (remaining >= 0) {
next();
} else {
callback();
}
});
})();
});
};
function read(url, callback) {
var done = function(reply) {
done = function() {};
callback(reply);
};
var options = parse(url);
options.headers = {
"Authorization": "Token " + token,
"User-Agent": "UglifyJS",
};
get(options, function(response) {
var chunks = [];
response.setEncoding("utf8");
response.on("data", function(chunk) {
chunks.push(chunk);
}).on("end", function() {
var reply;
try {
reply = JSON.parse(chunks.join(""))
} catch (e) {}
done(reply);
}).on("error", function() {
done();
});
}).on("error", function() {
done();
});
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +1,71 @@
var actions = require("./actions");
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 args = [
"--max-old-space-size=2048",
"test/ufuzz",
];
var iterations;
switch (process.argv.length) {
case 3:
iterations = +process.argv[2];
args.push(iterations);
break;
case 5:
actions.init(process.argv[2], process.argv[3], +process.argv[4]);
break;
default:
throw new Error("invalid parameters");
}
var tasks = [ run(), run() ];
if (iterations) return;
var alive = setInterval(function() {
actions.should_stop(function() {
clearInterval(alive);
tasks.forEach(function(kill) {
kill();
});
});
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);
}, 8 * 60 * 1000);
function run() {
var child, stdout, stderr, log;
spawn();
return function() {
clearInterval(log);
child.removeListener("exit", respawn);
child.kill();
}, endTime - Date.now());
};
function spawn() {
child = child_process.spawn("node", args, {
stdio: [ "ignore", "pipe", "pipe" ]
}).on("exit", respawn);
stdout = "";
child.stdout.on("data", function(data) {
stdout += data;
});
stderr = "";
child.stderr.on("data", trap).pipe(process.stdout);
log = setInterval(function() {
stdout = stdout.replace(/[^\r\n]+\r(?=[^\r\n]+\r)/g, "");
var end = stdout.lastIndexOf("\r");
if (end < 0) return;
console.log(stdout.slice(0, end));
stdout = stdout.slice(end + 1);
}, 5 * 60 * 1000);
}
function respawn() {
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
clearInterval(keepAlive);
clearTimeout(timer);
spawn(endTime);
clearInterval(log);
if (!iterations) {
spawn();
} else if (process.exitCode) {
tasks.forEach(function(kill) {
kill();
});
}
}
function trap(data) {

456
tools/domprops.html Normal file
View File

@@ -0,0 +1,456 @@
<!doctype html>
<html>
<body>
<script>
!function(G) {
var domprops = [];
var objs = [ G ];
var tagNames = [
"a",
"abbr",
"acronym",
"address",
"applet",
"area",
"article",
"aside",
"audio",
"b",
"base",
"basefont",
"bdi",
"bdo",
"bgsound",
"big",
"blink",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"checked",
"cite",
"code",
"col",
"colgroup",
"command",
"comment",
"compact",
"content",
"data",
"datalist",
"dd",
"declare",
"defer",
"del",
"details",
"dfn",
"dialog",
"dir",
"disabled",
"div",
"dl",
"dt",
"element",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"font",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"image",
"img",
"input",
"ins",
"isindex",
"ismap",
"kbd",
"keygen",
"label",
"legend",
"li",
"link",
"listing",
"main",
"map",
"mark",
"marquee",
"math",
"menu",
"menuitem",
"meta",
"meter",
"multicol",
"multiple",
"nav",
"nextid",
"nobr",
"noembed",
"noframes",
"nohref",
"noresize",
"noscript",
"noshade",
"nowrap",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"plaintext",
"pre",
"progress",
"q",
"rb",
"readonly",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"selected",
"shadow",
"slot",
"small",
"source",
"spacer",
"span",
"strike",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tt",
"u",
"ul",
"var",
"video",
"wbr",
"xmp",
"XXX",
];
for (var n = 0; n < tagNames.length; n++) {
add(document.createElement(tagNames[n]));
}
var nsNames = {
"http://www.w3.org/1998/Math/MathML": [
"annotation",
"annotation-xml",
"maction",
"maligngroup",
"malignmark",
"math",
"menclose",
"merror",
"mfenced",
"mfrac",
"mglyph",
"mi",
"mlabeledtr",
"mlongdiv",
"mmultiscripts",
"mn",
"mo",
"mover",
"mpadded",
"mphantom",
"mprescripts",
"mroot",
"mrow",
"ms",
"mscarries",
"mscarry",
"msgroup",
"msline",
"mspace",
"msqrt",
"msrow",
"mstack",
"mstyle",
"msub",
"msubsup",
"msup",
"mtable",
"mtd",
"mtext",
"mtr",
"munder",
"munderover",
"none",
"semantics",
],
"http://www.w3.org/2000/svg": [
"a",
"altGlyph",
"altGlyphDef",
"altGlyphItem",
"animate",
"animateColor",
"animateMotion",
"animateTransform",
"circle",
"clipPath",
"color-profile",
"cursor",
"defs",
"desc",
"discard",
"ellipse",
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feDropShadow",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence",
"filter",
"font",
"font-face",
"font-face-format",
"font-face-name",
"font-face-src",
"font-face-uri",
"foreignObject",
"g",
"glyph",
"glyphRef",
"hatch",
"hatchpath",
"hkern",
"image",
"line",
"linearGradient",
"marker",
"mask",
"mesh",
"meshgradient",
"meshpatch",
"meshrow",
"metadata",
"missing-glyph",
"mpath",
"path",
"pattern",
"polygon",
"polyline",
"radialGradient",
"rect",
"script",
"set",
"solidcolor",
"stop",
"style",
"svg",
"switch",
"symbol",
"text",
"textPath",
"title",
"tref",
"tspan",
"unknown",
"use",
"view",
"vkern",
],
};
if (document.createElementNS) for (var ns in nsNames) {
for (var n = 0; n < nsNames[ns].length; n++) {
add(document.createElementNS(ns, nsNames[ns][n]));
}
}
var skips = [
G.alert,
G.back,
G.blur,
G.captureEvents,
G.clearImmediate,
G.clearInterval,
G.clearTimeout,
G.close,
G.confirm,
G.console,
G.dump,
G.fetch,
G.find,
G.focus,
G.forward,
G.getAttention,
G.history,
G.home,
G.location,
G.moveBy,
G.moveTo,
G.navigator,
G.open,
G.openDialog,
G.print,
G.process,
G.prompt,
G.resizeBy,
G.resizeTo,
G.setImmediate,
G.setInterval,
G.setTimeout,
G.showModalDialog,
G.sizeToContent,
G.stop,
];
var types = [];
var interfaces = [
"beforeunloadevent",
"compositionevent",
"customevent",
"devicemotionevent",
"deviceorientationevent",
"dragevent",
"event",
"events",
"focusevent",
"hashchangeevent",
"htmlevents",
"keyboardevent",
"messageevent",
"mouseevent",
"mouseevents",
"storageevent",
"svgevents",
"textevent",
"touchevent",
"uievent",
"uievents",
];
var i = 0, full = false;
var addEvent = document.createEvent ? function(type) {
if (~indexOf(types, type)) return;
types.push(type);
for (var j = 0; j < interfaces.length; j++) try {
var event = document.createEvent(interfaces[j]);
event.initEvent(type, true, true);
add(event);
} catch (e) {}
} : function() {};
var scanProperties = Object.getOwnPropertyNames ? function(o, fn) {
var names = Object.getOwnPropertyNames(o);
names.forEach(fn);
for (var k in o) if (!~indexOf(names, k)) fn(k);
} : function(o, fn) {
for (var k in o) fn(k);
};
setTimeout(function next() {
for (var j = 10; --j >= 0 && i < objs.length; i++) {
var o = objs[i];
var skip = ~indexOf(skips, o);
try {
scanProperties(o, function(k) {
if (!~indexOf(domprops, k)) domprops.push(k);
if (/^on/.test(k)) addEvent(k.slice(2));
if (!full) try {
add(o[k]);
} catch (e) {}
});
} catch (e) {}
if (skip || full) continue;
try {
add(o.__proto__);
} catch (e) {}
try {
add(o.prototype);
} catch (e) {}
try {
add(new o());
} catch (e) {}
try {
add(o());
} catch (e) {}
}
if (!full && objs.length > 20000) {
alert(objs.length);
full = true;
}
if (i < objs.length) {
setTimeout(next, 0);
} else {
document.write('<pre>[\n "' + domprops.sort().join('",\n "').replace(/&/g, "&amp;").replace(/</g, "&lt;") + '"\n]</pre>');
}
}, 0);
function add(o) {
if (o) switch (typeof o) {
case "function":
case "object":
if (!~indexOf(objs, o)) objs.push(o);
}
}
function indexOf(list, value) {
var j = list.length;
while (--j >= 0) {
if (list[j] === value) break;
}
return j;
}
}(function() {
return this;
}());
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,540 +0,0 @@
<!doctype html>
<html>
<body>
<script>
!function() {
var names = [];
var scanned = [];
var to_scan = [];
function scan(obj) {
if (obj && typeof obj == "object" && !~scanned.indexOf(obj)) {
scanned.push(obj);
to_scan.push(obj);
}
}
scan(self);
[
"a",
"abbr",
"acronym",
"address",
"applet",
"area",
"article",
"aside",
"audio",
"b",
"base",
"basefont",
"bdi",
"bdo",
"bgsound",
"big",
"blink",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"checked",
"cite",
"code",
"col",
"colgroup",
"command",
"comment",
"compact",
"content",
"data",
"datalist",
"dd",
"declare",
"defer",
"del",
"details",
"dfn",
"dialog",
"dir",
"disabled",
"div",
"dl",
"dt",
"element",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"font",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"image",
"img",
"input",
"ins",
"isindex",
"ismap",
"kbd",
"keygen",
"label",
"legend",
"li",
"link",
"listing",
"main",
"map",
"mark",
"marquee",
"math",
"menu",
"menuitem",
"meta",
"meter",
"multicol",
"multiple",
"nav",
"nobr",
"noembed",
"noframes",
"nohref",
"noresize",
"noscript",
"noshade",
"nowrap",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"plaintext",
"pre",
"progress",
"q",
"rb",
"readonly",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"selected",
"shadow",
"small",
"source",
"spacer",
"span",
"strike",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tt",
"u",
"ul",
"var",
"video",
"wbr",
"xmp",
"XXX",
].forEach(function(tag) {
scan(document.createElement(tag));
});
[
"abort",
"absolutedeviceorientation",
"activate",
"active",
"addsourcebuffer",
"addstream",
"addtrack",
"afterprint",
"afterscriptexecute",
"afterupdate",
"animationcancel",
"animationend",
"animationiteration",
"animationstart",
"appinstalled",
"audioend",
"audioprocess",
"audiostart",
"autocomplete",
"autocompleteerror",
"auxclick",
"beforeactivate",
"beforecopy",
"beforecut",
"beforedeactivate",
"beforeeditfocus",
"beforeinstallprompt",
"beforepaste",
"beforeprint",
"beforescriptexecute",
"beforeunload",
"beforeupdate",
"blocked",
"blur",
"bounce",
"boundary",
"cached",
"cancel",
"candidatewindowhide",
"candidatewindowshow",
"candidatewindowupdate",
"canplay",
"canplaythrough",
"cellchange",
"change",
"chargingchange",
"chargingtimechange",
"checking",
"click",
"close",
"compassneedscalibration",
"complete",
"connect",
"connecting",
"connectionstatechange",
"contextmenu",
"controllerchange",
"controlselect",
"copy",
"cuechange",
"cut",
"dataavailable",
"datachannel",
"datasetchanged",
"datasetcomplete",
"dblclick",
"deactivate",
"devicechange",
"devicelight",
"devicemotion",
"deviceorientation",
"deviceorientationabsolute",
"deviceproximity",
"dischargingtimechange",
"disconnect",
"display",
"downloading",
"drag",
"dragend",
"dragenter",
"dragexit",
"dragleave",
"dragover",
"dragstart",
"drop",
"durationchange",
"emptied",
"encrypted",
"end",
"ended",
"enter",
"enterpictureinpicture",
"error",
"errorupdate",
"exit",
"filterchange",
"finish",
"focus",
"focusin",
"focusout",
"freeze",
"fullscreenchange",
"fullscreenerror",
"gesturechange",
"gestureend",
"gesturestart",
"gotpointercapture",
"hashchange",
"help",
"icecandidate",
"iceconnectionstatechange",
"icegatheringstatechange",
"inactive",
"input",
"invalid",
"keydown",
"keypress",
"keyup",
"languagechange",
"layoutcomplete",
"leavepictureinpicture",
"levelchange",
"load",
"loadeddata",
"loadedmetadata",
"loadend",
"loading",
"loadingdone",
"loadingerror",
"loadstart",
"losecapture",
"lostpointercapture",
"mark",
"message",
"messageerror",
"mousedown",
"mouseenter",
"mouseleave",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"mousewheel",
"move",
"moveend",
"movestart",
"mozfullscreenchange",
"mozfullscreenerror",
"mozorientationchange",
"mozpointerlockchange",
"mozpointerlockerror",
"mscontentzoom",
"msfullscreenchange",
"msfullscreenerror",
"msgesturechange",
"msgesturedoubletap",
"msgestureend",
"msgesturehold",
"msgesturestart",
"msgesturetap",
"msgotpointercapture",
"msinertiastart",
"mslostpointercapture",
"msmanipulationstatechanged",
"msneedkey",
"msorientationchange",
"mspointercancel",
"mspointerdown",
"mspointerenter",
"mspointerhover",
"mspointerleave",
"mspointermove",
"mspointerout",
"mspointerover",
"mspointerup",
"mssitemodejumplistitemremoved",
"msthumbnailclick",
"negotiationneeded",
"nomatch",
"noupdate",
"obsolete",
"offline",
"online",
"open",
"orientationchange",
"pagechange",
"pagehide",
"pageshow",
"paste",
"pause",
"play",
"playing",
"pluginstreamstart",
"pointercancel",
"pointerdown",
"pointerenter",
"pointerleave",
"pointerlockchange",
"pointerlockerror",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"popstate",
"progress",
"propertychange",
"ratechange",
"reading",
"readystatechange",
"rejectionhandled",
"removesourcebuffer",
"removestream",
"removetrack",
"reset",
"resize",
"resizeend",
"resizestart",
"resourcetimingbufferfull",
"result",
"resume",
"rowenter",
"rowexit",
"rowsdelete",
"rowsinserted",
"scroll",
"search",
"seeked",
"seeking",
"select",
"selectionchange",
"selectstart",
"show",
"signalingstatechange",
"soundend",
"soundstart",
"sourceclose",
"sourceclosed",
"sourceended",
"sourceopen",
"speechend",
"speechstart",
"stalled",
"start",
"statechange",
"stop",
"storage",
"storagecommit",
"submit",
"success",
"suspend",
"textinput",
"timeout",
"timeupdate",
"toggle",
"touchcancel",
"touchend",
"touchmove",
"touchstart",
"track",
"transitioncancel",
"transitionend",
"transitionrun",
"transitionstart",
"unhandledrejection",
"unload",
"updateready",
"upgradeneeded",
"userproximity",
"versionchange",
"visibilitychange",
"voiceschanged",
"volumechange",
"vrdisplayactivate",
"vrdisplayconnect",
"vrdisplaydeactivate",
"vrdisplaydisconnect",
"vrdisplaypresentchange",
"waiting",
"waitingforkey",
"warning",
"webkitanimationend",
"webkitanimationiteration",
"webkitanimationstart",
"webkitcurrentplaybacktargetiswirelesschanged",
"webkitfullscreenchange",
"webkitfullscreenerror",
"webkitkeyadded",
"webkitkeyerror",
"webkitkeymessage",
"webkitneedkey",
"webkitorientationchange",
"webkitplaybacktargetavailabilitychanged",
"webkitpointerlockchange",
"webkitpointerlockerror",
"webkitresourcetimingbufferfull",
"webkittransitionend",
"wheel",
"zoom",
].forEach(function(type) {
[
"beforeunloadevent",
"compositionevent",
"customevent",
"devicemotionevent",
"deviceorientationevent",
"dragevent",
"event",
"events",
"focusevent",
"hashchangeevent",
"htmlevents",
"keyboardevent",
"messageevent",
"mouseevent",
"mouseevents",
"storageevent",
"svgevents",
"textevent",
"touchevent",
"uievent",
"uievents",
].forEach(function(interface) {
try {
var event = document.createEvent(interface);
event.initEvent(type, true, true);
scan(event);
} catch (e) {}
});
});
var obj;
while (obj = to_scan.shift()) {
var proto = obj;
do {
Object.getOwnPropertyNames(proto).forEach(function(name) {
var visited = ~names.indexOf(name);
if (!visited) names.push(name);
try {
scan(obj[name]);
if (visited) return;
if (/^create/.test(name)) {
scan(obj[name]());
}
if (/^[A-Z]/.test(name)) {
scan(new obj[name]());
}
} catch (e) {}
});
} while (proto = Object.getPrototypeOf(proto));
}
names.sort();
document.write('<pre>[\n "');
document.write(names.join('",\n "'));
document.write('"\n]</pre>');
}();
</script>
</body>
</html>