Compare commits

...

362 Commits

Author SHA1 Message Date
Alex Lam S.L
1f3f8f25eb harmony-v3.3.5 2018-01-08 00:30:45 +08:00
alexlamsl
4b1799ecdd disable reminify()
fix-up for #2708
2018-01-07 22:32:29 +08:00
alexlamsl
7a8eff62ca Merge branch 'master' into harmony-v3.3.5 2018-01-07 20:35:53 +08:00
Alex Lam S.L
9336cc8247 v3.3.5 2018-01-07 11:51:36 +00:00
Alex Lam S.L
9809567dfc improve process.exit() workaround (#2741)
- use public API
- fix issue with Node.js 0.10 on WIndows
2018-01-07 17:53:50 +08:00
Alex Lam S.L
1ee8be8d91 fix recursive function inline (#2738)
fixes #2737
2018-01-07 15:31:24 +08:00
Alex Lam S.L
8430c2f9f8 enable AppVeyor CI (#2739) 2018-01-07 14:14:58 +08:00
Alex Lam S.L
659c8a7632 handle trailing line comments correctly (#2736)
fixes #2734
2018-01-06 21:05:21 +08:00
Alex Lam S.L
3564b4f20d compress RegExp() in unsafe (#2735) 2018-01-06 21:04:47 +08:00
Alex Lam S.L
3505a3604a enhance unsafe_proto (#2733) 2018-01-06 06:16:51 +08:00
kzc
9b1bc6c014 ufuzz: add strings "a", "b", "c" to VALUES (#2732) 2018-01-06 05:54:53 +08:00
Alex Lam S.L
9f23185f2b fix corner case with arguments as function name (#2729)
fixes #2728
2018-01-05 22:21:18 +08:00
Alex Lam S.L
b82feb9302 improve if_return (#2727) 2018-01-05 20:24:30 +08:00
Alex Lam S.L
7f2a591c7e warn on deprecated features (#2726)
- `function.arguments`
- `function.callers`

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

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

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

where `fn` can be `function` literal or symbol reference linked through `reduce_vars`
2017-12-18 16:23:39 +08:00
Alex Lam S.L
0b0eac1d5d drop property assignment to constants (#2612) 2017-12-18 12:07:53 +08:00
kzc
85bfa17139 fix slowness in unused for blocks (#2614)
fixes #2609
2017-12-18 12:06:14 +08:00
Alex Lam S.L
b29fc8b27c improve transversal efficiency in collapse_vars (#2611)
fixes #2603
2017-12-18 03:00:05 +08:00
kzc
80c8dfcde6 fix export default of anonymous generators and async functions (#2607)
fixes #2606
2017-12-18 00:11:52 +08:00
Alex Lam S.L
5de369fa67 export parse() (#2608) 2017-12-17 23:12:23 +08:00
Alex Lam S.L
7918a50d52 improve reset_opt_flags() (#2610) 2017-12-17 23:01:08 +08:00
Alex Lam S.L
21794c9b8d account for catch variable when inline (#2605)
fixes #2604
2017-12-16 15:21:09 +08:00
Alex Lam S.L
6c686ce593 fix nested inline (#2602)
fixes #2601
2017-12-16 02:16:35 +08:00
Alex Lam S.L
db902af4c6 fix escape analysis on || and && (#2600)
fixes #2598
2017-12-15 19:48:14 +08:00
Alex Lam S.L
7d6907cb99 fix dead_code on nested try (#2599)
fixes #2597
2017-12-15 19:41:28 +08:00
Alex Lam S.L
092d9affb8 fix reduce_vars on do...while (#2596) 2017-12-15 16:33:19 +08:00
Alex Lam S.L
8f681b1d17 handle inline of function arguments (#2590)
fixes #2476
2017-12-15 13:28:30 +08:00
Alex Lam S.L
90313875f7 inline single-use function across loop (#2594) 2017-12-14 19:24:54 +08:00
Alex Lam S.L
3f18a61532 fix reduce_vars on single AST_Defun reference across loop (#2593) 2017-12-14 18:47:05 +08:00
Alex Lam S.L
02a6ce07eb improve reduce_vars (#2592)
- account for hoisting nature of `var`
2017-12-14 15:32:13 +08:00
Alex Lam S.L
738fd52bc4 improve collapse_vars (#2591)
- handle single-use assignments other than `AST_VarDef`
- scan `AST_Call` for candidates
2017-12-14 15:31:35 +08:00
kzc
d18979bb23 improve dead_code tests (#2589)
for #2588
2017-12-14 12:12:06 +08:00
Alex Lam S.L
8266993c6e fix dead_code on return/throw within try (#2588) 2017-12-14 04:38:21 +08:00
Alex Lam S.L
9a137e8613 drop local assign-only variable in return (#2587) 2017-12-14 02:59:59 +08:00
Alex Lam S.L
ef618332ea fold cascade functionality into collapse_vars (#2586) 2017-12-14 01:20:36 +08:00
Alex Lam S.L
7f418978c9 recover lost opportunities from #2574 (#2584) 2017-12-13 18:20:53 +08:00
Alex Lam S.L
04cc395c35 improve collapse_vars on side-effect-free replacements (#2583) 2017-12-13 04:52:54 +08:00
Alex Lam S.L
e008dc1bde minor clean-up for IIFE (#2582)
- faster exact type match
- aggressively convert to `!`
2017-12-13 01:27:26 +08:00
Alex Lam S.L
ddf96cfda2 avoid Function.prototype pollution by test/sandbox.js (#2581) 2017-12-12 05:02:01 +08:00
Alex Lam S.L
ebfd5c5c74 fix AST_VarDef.may_throw() (#2580) 2017-12-12 03:30:25 +08:00
Alex Lam S.L
f2ad542679 fix collapse_vars on switch (#2578) 2017-12-11 18:11:09 +08:00
Alex Lam S.L
c43118be4f remove unused code (#2579)
fixes #2577
2017-12-11 17:39:08 +08:00
Alex Lam S.L
93f3b2b114 escape consecutive unpaired surrogates (#2576)
fixes #2569
2017-12-11 01:15:44 +08:00
Alex Lam S.L
bf000beae7 rename tests (#2575) 2017-12-11 00:24:54 +08:00
Alex Lam S.L
f8ff349ba7 harmony-v3.2.2 2017-12-11 00:16:36 +08:00
Alex Lam S.L
0e16d92786 handle exceptional flow correctly in collapse_vars (#2574)
fixes #2571
2017-12-11 00:16:02 +08:00
alexlamsl
f2b179ae94 fix escape analysis for AST_Expansion 2017-12-10 23:05:22 +08:00
alexlamsl
c7e8fc4830 fix escape analysis for `AST_Await
fixes #2566
2017-12-10 23:03:29 +08:00
alexlamsl
f778a0aa01 fix escape analysis for AST_Yield
fixes #2565
2017-12-10 23:02:20 +08:00
alexlamsl
7fd4b66eaa fix tests 2017-12-10 14:16:54 +08:00
alexlamsl
21c986ff5b Merge branch 'master' into harmony-v3.2.2 2017-12-10 14:12:24 +08:00
Alex Lam S.L
2441827408 v3.2.2 2017-12-10 13:46:17 +08:00
Alex Lam S.L
0aff037a35 improve unused on assign-only symbols (#2568) 2017-12-09 06:19:29 +08:00
Alex Lam S.L
74a2f53683 fix escape analysis for AST_Throw (#2564) 2017-12-08 02:54:37 +08:00
Alex Lam S.L
e20935c3f2 fix escape analysis for AST_Conditional & AST_Sequence (#2563)
fixes #2560
2017-12-08 01:50:38 +08:00
Alex Lam S.L
3e34f62a1c account for side-effects in conditional call inversion (#2562)
fixes #2560
2017-12-08 01:15:31 +08:00
Alex Lam S.L
d21cb84696 eliminate noop calls more aggressively (#2559) 2017-12-07 01:22:08 +08:00
Alex Lam S.L
3dd495ecdd improve if_return (#2558)
`return void x()` => `x()`
2017-12-07 01:01:52 +08:00
Alex Lam S.L
87bae623e9 simplify computed properties for methods, getters & setters (#2555)
fixes #2554
2017-12-04 00:18:48 +08:00
Alex Lam S.L
606f7a5b37 harmony-v3.2.1 2017-12-03 13:51:27 +08:00
alexlamsl
b91a2e018a fix tests 2017-12-03 12:14:31 +08:00
alexlamsl
c9dbe9deb1 Merge branch 'master' into harmony-v3.2.1 2017-12-03 11:59:41 +08:00
Alex Lam S.L
b9f3ddfb30 v3.2.1 2017-12-03 11:39:51 +08:00
Alex Lam S.L
77332a0315 fix dead_code on for (#2552) 2017-12-02 15:46:05 +08:00
Alex Lam S.L
85c56adbd1 more tests for #2535 (#2551) 2017-12-02 02:26:56 +08:00
Alex Lam S.L
8da3754e51 improve evaluate on typeof (#2550)
- gated through `typeofs`
2017-12-02 02:18:33 +08:00
Alex Lam S.L
9a6b11f8e6 improve boolean compression (#2548)
fixes #2535
2017-12-01 22:41:35 +08:00
Alex Lam S.L
7ac6fdcc99 improve switch case compression (#2547) 2017-12-01 14:32:00 +08:00
Alex Lam S.L
f6610baaa8 improve AST_For.init & AST_Switch.expression compression (#2546) 2017-12-01 12:53:59 +08:00
Alex Lam S.L
09b320e8a5 convert to number under boolean context (#2545) 2017-12-01 12:52:36 +08:00
Alex Lam S.L
5a1e99d713 improve compression of if conditions (#2544) 2017-12-01 06:18:31 +08:00
Alex Lam S.L
b762f2d6f4 improve compression of loop conditions (#2543) 2017-12-01 05:52:33 +08:00
Alex Lam S.L
172079a47f improve code reuse (#2542) 2017-12-01 03:40:46 +08:00
Alex Lam S.L
c58d3936a3 fix corner case in call binding (#2541) 2017-12-01 03:18:20 +08:00
Alex Lam S.L
18302bf8e9 backport test from #2526 (#2534) 2017-11-29 13:32:00 +08:00
Alex Lam S.L
bc5047c1e7 fix inline on nested substitutions (#2533)
fixes #2531
2017-11-29 13:31:41 +08:00
kzc
1885f91f13 document top level minify() option safari10 (#2532) 2017-11-29 05:48:33 +08:00
Alex Lam S.L
736c366d93 introduce --safari10 (#2530) 2017-11-29 03:34:47 +08:00
kzc
1646c5844f document the new output option safari10 (#2529) 2017-11-29 02:29:23 +08:00
Alex Lam S.L
aacf760fb4 add Safari workaround for await (#2528)
fixes #2344
2017-11-29 00:20:36 +08:00
Alex Lam S.L
755e2a62c6 extend hoist_props to AST_Arrow & AST_Class (#2527)
fixes #2503
2017-11-28 22:54:44 +08:00
Alex Lam S.L
62d2817d6c reduce this in block scopes (#2526)
fixes #2455
2017-11-28 22:54:21 +08:00
Alex Lam S.L
37cbd7080c replace single-use class definitions (#2524)
fixes #2416
2017-11-28 20:57:15 +08:00
Alex Lam S.L
206a54a746 fix nested hoist_props substitution (#2523)
fixes #2519
2017-11-28 14:39:00 +08:00
Alex Lam S.L
32def5ebf5 improve synergy between collapse_vars & unused (#2521) 2017-11-28 14:02:39 +08:00
Alex Lam S.L
ecc9f6b770 drop assignment in AST_VarDef.value (#2522)
fixes #2516
2017-11-28 13:08:40 +08:00
Alex Lam S.L
b84c99ef5c harmony-v3.2.0 2017-11-26 06:02:49 +08:00
alexlamsl
4f08c2f504 Merge branch 'master' into harmony-v3.2.0 2017-11-26 04:23:57 +08:00
Alex Lam S.L
b37a68c84f v3.2.0 2017-11-26 04:08:35 +08:00
Alex Lam S.L
c141ae6f8d fix argument/atom collision by properties (#2514)
fixes #2513
2017-11-25 22:52:46 +08:00
Alex Lam S.L
97c464dbf5 fix wording and formatting (#2512) 2017-11-25 19:07:46 +08:00
kzc
ba4894af18 document top level minify option keep_classnames (#2511) 2017-11-25 16:33:03 +08:00
Alex Lam S.L
f1e3ef5262 separate keep_classnames & keep_fnames (#2510)
fixes #2418
2017-11-25 16:31:52 +08:00
Alex Lam S.L
3b28b915eb extend escape analysis on constant expression properties (#2509)
fixes #2508
2017-11-24 14:07:39 +08:00
Alex Lam S.L
eb001dc1d9 fix argument/atom collision by collapse_vars (#2507)
fixes #2506
2017-11-24 07:26:22 +08:00
Alex Lam S.L
aa9bdf416e make AST_Lambda.contains_this() less magical (#2505) 2017-11-24 07:03:37 +08:00
Alex Lam S.L
bbf38dc9c0 fix reduce_vars on arrow functions with this (#2504)
fixes #2496
2017-11-24 06:21:49 +08:00
Alex Lam S.L
8987780db6 eliminate invalid state caching in collapse_vars (#2502)
fixes #2497
2017-11-24 04:12:37 +08:00
Alex Lam S.L
30cfea2e7a fix rename (#2501)
- suppress spurious `rename` from `commander`
- handle `AST_SymbolCatch` correctly
2017-11-24 03:05:43 +08:00
kzc
3d8341a7ab fix properties for array literal with spread (#2499)
fixes #2498
2017-11-24 02:04:26 +08:00
Alex Lam S.L
f4e2fb9864 expand symbol space to improve compression (#2460)
- give globally distinct names to distinct variables
- improve ability to compress cross-scoped
- introduce `options.rename` to `minify()`
- default `true` if both `compress` & `mangle`
2017-11-19 19:29:51 +08:00
Alex Lam S.L
567cb0e4e3 harmony-v3.1.10 2017-11-19 15:53:22 +08:00
Alex Lam S.L
b80062c490 enable hoist_props by default (#2492) 2017-11-19 14:56:23 +08:00
alexlamsl
227b58812d Merge branch 'master' into harmony-v3.1.10 2017-11-19 14:34:27 +08:00
kzc
f25bd13be6 fix keyword shorthand property output for ecma >= 6 (#2493)
fixes #2491
2017-11-19 13:53:42 +08:00
Alex Lam S.L
667fc4d08b v3.1.10 2017-11-18 23:56:33 +08:00
kzc
6142117cdd document the webkit output option (#2490)
- workaround for WebKit bugs
- PhantomJS users should enable this output option

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

fixes #2436
2017-11-12 22:31:47 +08:00
Alex Lam S.L
9632f79e46 harmony-v3.1.9 2017-11-11 19:21:09 +08:00
alexlamsl
a3fbb27194 update tests 2017-11-11 15:57:47 +08:00
alexlamsl
11c0b1e1f9 Merge branch 'master' into harmony-v3.1.9 2017-11-11 15:45:34 +08:00
Alex Lam S.L
346fa12e0e v3.1.9 2017-11-11 15:31:13 +08:00
Alex Lam S.L
cda27b0970 extend reduce_funcs to cover cross-scope substitutions (#2469)
fixes #2468
2017-11-11 15:30:17 +08:00
Alex Lam S.L
3c74047368 implement compress option reduce_funcs (#2466)
- inline single-use function declarations as expressions when permissible
- depend on `reduce_vars`
- enabled by default
- disable for speed critical code

fixes #2464
2017-11-11 05:59:35 +08:00
Alex Lam S.L
650d5d5c9b suppress hoist_props on export (#2463)
Miscellaneous
- fix double semi-colons from `beautify` in `export`

fixes #2462
2017-11-10 17:38:31 +08:00
Alex Lam S.L
94525d859f fix object literal tracing in reduce_vars (#2461) 2017-11-10 05:47:10 +08:00
Alex Lam S.L
1127a2caf3 fix multiple nested function substitutions (#2458)
fixes #2449
2017-11-09 23:30:00 +08:00
Alex Lam S.L
246d9d4e83 remove hack in collapse_vars (#2457)
fixes #2456
2017-11-09 20:00:58 +08:00
Alex Lam S.L
4c0b0177b6 preserve function identity in reduce_vars (#2451)
fixes #2450
2017-11-08 03:28:46 +08:00
Alex Lam S.L
dd0a36119b fix const under collapse_vars without unused (#2454)
fixes #2453
2017-11-08 02:10:46 +08:00
Alex Lam S.L
94b19a9c46 harmony-v3.1.8 2017-11-07 06:05:40 +08:00
alexlamsl
bcf95ac02c update tests 2017-11-07 04:49:57 +08:00
alexlamsl
e11cec1ab8 Merge branch 'master' into harmony 2017-11-07 04:30:40 +08:00
Alex Lam S.L
38bfb73f06 v3.1.8 2017-11-07 03:55:16 +08:00
Alex Lam S.L
bbedbf4ea0 handle circular function reference gracefully (#2446)
fixes #2442
2017-11-07 02:37:23 +08:00
Alex Lam S.L
2cfb5aa7da account for eval & with in reduce_vars (#2441)
fixes #2440
2017-11-06 16:10:57 +08:00
Alex Lam S.L
6c45101870 consolidate & enhance unused (#2439)
- defer declaration removal in `collapse_vars`
- account for `AST_SymbolFunarg` in deduplication
- private accounting for `collapse_vars`
- avoid issues with identity reference due to deep cloning

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


fixes #2420
2017-11-04 00:31:37 +08:00
kzc
29bbc41dfe hoist_props: implement limited hoisting of class expressions (#2415) 2017-10-30 23:20:54 +08:00
Alex Lam S.L
a48f87abf2 compress new function containing this (#2417) 2017-10-30 23:19:27 +08:00
Alex Lam S.L
d535daa2c7 harmony-v3.1.6 2017-10-29 18:58:58 +08:00
alexlamsl
0a9cdb6c73 handle computed properties correctly 2017-10-29 17:46:25 +08:00
alexlamsl
3ae34177a6 merge #2391 & #2393 2017-10-29 17:14:52 +08:00
alexlamsl
086cb33163 Merge branch 'master' into harmony-v3.1.6 2017-10-29 13:23:39 +08:00
Alex Lam S.L
2fd927a7cc v3.1.6 2017-10-29 12:38:10 +08:00
Alex Lam S.L
8428326ea1 enhance properties (#2412)
- trim array items only if `side_effects`
- extend to non-identifier properties
2017-10-29 04:11:26 +08:00
Alex Lam S.L
6371e2ee63 consistently reduce const safe literals (#2411)
fixes #2406
2017-10-28 11:36:44 +08:00
Alex Lam S.L
6ab73c7bd5 fix & improve AST_TemplateString (#2410)
- resolve `semicolons:false` ambiguity with tagged literals
- allow `side_effects` to work on template literals
- traverse `AST_TemplateString` properly

fixes #2401
2017-10-28 11:36:09 +08:00
Alex Lam S.L
31f8209193 remove dead code (#2405) 2017-10-27 14:28:09 +08:00
Alex Lam S.L
9b0f86f5a1 fix reduce_vars on AST_Array.length (#2404) 2017-10-27 02:33:37 +08:00
Alex Lam S.L
ee082ace1b compress self comparisons (#2398) 2017-10-26 01:16:12 +08:00
kzc
ae67a49850 document compress option hoist_props (#2399) 2017-10-25 14:03:43 +08:00
Alex Lam S.L
4178289c38 implement hoist_props (#2396)
fixes #2377
2017-10-25 03:38:11 +08:00
Alex Lam S.L
74ae16f9f8 fix unsafe reduce_vars on arrays & objects (#2397) 2017-10-24 22:10:36 +08:00
Tom MacWright
1968203d83 docs: Fix spelling and style (#2395) 2017-10-24 04:59:12 +08:00
Tom MacWright
2848596280 docs: Fix spelling and style (#2395) 2017-10-24 04:53:56 +08:00
Alex Lam S.L
86ea38a259 enhance unsafe evaluate of arrays & objects (#2394) 2017-10-24 02:58:30 +08:00
Alex Lam S.L
8a713e449f deduplicate declarations regardless of toplevel (#2393) 2017-10-23 01:00:50 +08:00
Alex Lam S.L
7d9a8596a9 fix dead_code on AST_Destructuring (#2392)
fixes #2383
2017-10-23 00:34:34 +08:00
Alex Lam S.L
24aa07855b safer properties transform (#2391)
`{ a: x, b: y }.a` => `[ x, y ][0]`
- `x` cannot be function containing `this`

`[ x, y, z ][1]` => `(x, z, y)`
- only if `z` is side-effect-free
2017-10-22 20:10:13 +08:00
Alex Lam S.L
5fd723f143 fix unsafe expansion of object literals (#2390) 2017-10-22 15:00:36 +08:00
Alex Lam S.L
516eaef50c fix unsafe evaluation of AST_Sub (#2389) 2017-10-22 13:14:15 +08:00
Alex Lam S.L
4ae1fb3ed8 fix unsafe evaluation of objects (#2388) 2017-10-22 04:19:40 +08:00
Alex Lam S.L
011123223b fix unsafe escape analysis in reduce_vars (#2387) 2017-10-22 03:23:31 +08:00
Alex Lam S.L
44352eb26a harmony-v3.1.5 2017-10-22 01:49:55 +08:00
alexlamsl
9f1c72ae28 update test
Sub-optimal result due to block scope.
2017-10-22 00:38:16 +08:00
alexlamsl
c60fa67827 Merge branch 'master' into harmony-v3.1.5 2017-10-22 00:35:00 +08:00
Alex Lam S.L
96439ca246 v3.1.5 2017-10-22 00:27:26 +08:00
Thomas Sauer
f9c57dfee0 Allow 'yield' as method name (#2382)
fixes #2381
2017-10-21 14:22:39 +08:00
Alex Lam S.L
c927cea632 unsafe fix-ups for #2351 (#2379) 2017-10-21 04:08:26 +08:00
Alex Lam S.L
9f4b98f8e4 backport #2374 (#2376) 2017-10-19 23:02:27 +08:00
Alex Lam S.L
0f2ef3367c enhance collapse_vars around lazy operations (#2369) 2017-10-19 04:52:00 +08:00
kzc
6bf5fea008 option formatting in docs (#2374)
- reintroduce compress documentation for keep_fnames and unsafe_methods
- reintroduce keep_fnames in mangle option docs
- order compress & mangle options
2017-10-18 05:23:53 +08:00
Alex Lam S.L
7e5b5cac97 fix AST_PropAccess in collapse_vars (take 3) (#2375)
Suppress scanning beyond assignment to `a.b`
2017-10-18 02:54:51 +08:00
Alex Lam S.L
c1346e06b7 clean up lazy operator detection (#2373) 2017-10-17 23:25:45 +08:00
Alex Lam S.L
0d2fe8e3ef fix AST_PropAccess in collapse_vars (take 2) (#2372)
fixes #2364
2017-10-17 22:59:15 +08:00
Alex Lam S.L
f2b9c11e2a fix AST_PropAccess in collapse_vars (#2370)
fixes #2364
2017-10-17 18:33:03 +08:00
Alex Lam S.L
b6a7ca292e deduplicate AST_Super & AST_This logic (#2366) 2017-10-17 04:19:53 +08:00
Alex Lam S.L
fe647b083e account for side-effects from AST_This in collapse_vars (#2365) 2017-10-17 01:18:55 +08:00
Alex Lam S.L
a89f126db6 harmony-v3.1.4 2017-10-16 14:28:28 +08:00
alexlamsl
d8ee2de95c adjust tests for #2351 2017-10-16 13:24:50 +08:00
alexlamsl
58a5608b66 Merge branch 'master' into harmony-v3.1.4 2017-10-16 12:32:50 +08:00
kzc
f496ac5c85 implement compress option computed_props (#2361)
transforms `{["computed"]: 1}` into `{computed: 1}`
2017-10-16 11:35:04 +08:00
Alex Lam S.L
dfe4f6c6de v3.1.4 2017-10-16 02:44:17 +08:00
Alex Lam S.L
a09c8ad666 update dependency (#2362)
- source-map@0.6.1
2017-10-16 02:41:22 +08:00
Alex Lam S.L
ec598c351b fix-ups for #2356 (#2360) 2017-10-15 22:33:55 +08:00
kzc
f79f737fb2 fix mangle of destructuring parameters with computed properties (#2359)
fixes #2349
2017-10-15 20:59:52 +08:00
Alex Lam S.L
eba0f93bc0 more tests for #2351 (#2357) 2017-10-12 02:58:25 +08:00
Roger Peppe
99800d4aa9 update README to include defaults (#2356)
fixes #2353
2017-10-12 02:56:02 +08:00
Tim Malone
70d56c951a Update README.md - sourceMappingURL directive note (#2355)
Moves this README note to underneath the 'url' rather than 'root' option.
2017-10-11 19:48:43 +08:00
Alex Lam S.L
b810e2f8da perform reduce_vars on safe literals (#2351)
- constant expression
- single reference
- same scope
- not across loop body
2017-10-09 12:25:06 +08:00
Alex Lam S.L
1abe14296e collapse a.b whenever safe (#2350) 2017-10-08 13:17:48 +08:00
kzc
336b1add4f fix unsafe join() on array literal with spread (#2347)
fixes #2345
2017-10-06 00:57:00 +08:00
Alex Lam S.L
873755b35c harmony-v3.1.3 2017-10-01 14:41:52 +08:00
alexlamsl
744032755d add tests for #2336 & #2337 2017-10-01 13:20:17 +08:00
alexlamsl
4fac8076b8 Merge branch 'master' into harmony-v3.1.3 2017-10-01 12:42:40 +08:00
Alex Lam S.L
6920e898d1 v3.1.3 2017-10-01 12:36:07 +08:00
Alex Lam S.L
dd71639264 enhance reduce_vars for AST_Accessor (#2339)
fixes #2336
2017-10-01 03:01:50 +08:00
Alex Lam S.L
2dcc552ce0 trap invalid use of reserved words (#2338)
fixes #2337
2017-10-01 02:10:41 +08:00
kzc
a020d2ead3 support dynamic import(), trap invalid use of export (#2335) 2017-09-28 18:43:09 +08:00
Alex Lam S.L
68645b28d3 harmony-v3.1.2 2017-09-24 11:13:25 +08:00
alexlamsl
aaa8212837 improve test for #2316 2017-09-24 02:23:38 +08:00
alexlamsl
bd84007cf4 Merge branch 'master' into harmony-v3.1.2 2017-09-24 02:20:47 +08:00
Alex Lam S.L
55387e8fd0 v3.1.2 2017-09-24 02:02:04 +08:00
GUENEGO Jean-Louis
1241600013 mangle: do not mangle reserved class (#2317)
fixes #2316
2017-09-24 00:08:47 +08:00
kzc
7e3e9da860 fix "use asm" numeric output (#2328)
fixes #2324
2017-09-21 04:42:40 +08:00
kzc
a784717fe2 allow RegExp for unsafe_methods compress option (#2327) 2017-09-21 00:48:16 +08:00
Alex Lam S.L
00f509405b suppress collapse_vars of this into "use strict" (#2326)
fixes #2319
2017-09-20 05:23:20 +08:00
kzc
e8235657e4 add new compress option unsafe_methods for ecma >= 6 (#2325)
fixes #2321
2017-09-20 00:15:54 +08:00
Alex Lam S.L
c46b9f361a harmony-v3.1.1 2017-09-17 15:33:55 +08:00
alexlamsl
3b0b4d6abf handle AST_Super in collapse_vars & side_effects 2017-09-17 05:09:36 +08:00
alexlamsl
d73500e8d1 Merge branch 'master' into harmony-v3.1.1 2017-09-17 04:43:43 +08:00
Alex Lam S.L
aceb0af36b v3.1.1 2017-09-17 04:36:27 +08:00
Alex Lam S.L
4f0953f7e9 handle LHS side-effects on cascade & collapse_vars (#2314)
fixes #2313
2017-09-16 11:45:19 +08:00
Alex Lam S.L
182a47bfb1 improve source mapping (#2312)
fixes #2310
2017-09-15 12:46:48 +08:00
Alex Lam S.L
d8685f528d harmony-v3.1.0 2017-09-10 20:51:33 +08:00
alexlamsl
8891495789 Merge branch 'master' into harmony-v3.1.0 2017-09-10 15:39:33 +08:00
Alex Lam S.L
cd27f4ec38 v3.1.0 2017-09-10 15:17:24 +08:00
Mateusz Burzyński
8158b1bdcf Testing all leading comments against being PURE comments (#2305) 2017-09-10 02:08:15 +08:00
Alex Lam S.L
aacf3edc68 extend unsafe on pure global functions (#2303) 2017-09-07 22:08:34 +08:00
kzc
8b89072190 add Date and other known globals to unsafe compress option (#2302) 2017-09-07 02:44:26 +08:00
Alex Lam S.L
395a17ccda fix collapse_vars on default function argument (#2299)
Avoid collision with local variable `undefined` under certain corner cases.

fixes #2298
2017-09-04 02:32:33 +08:00
Alex Lam S.L
3f355866cf correctly count declarations after hoist_vars (#2297)
fixes #2295
2017-09-03 17:23:31 +08:00
kzc
2779a29a86 avoid generating ternary with spread (#2293)
fixes #2292
2017-08-31 00:57:07 +08:00
David Šanda
71d52f147d Fix CLI example for mangle reserved list of names (#2294) 2017-08-31 00:55:32 +08:00
David Šanda
eb7adaa6fc Fix CLI source-maps examples (#2291)
fixes #2284
2017-08-29 23:49:20 +08:00
Alex Lam S.L
e5cf7972ea fix unused patching of AST_For.init blocks (#2289)
fixes #2288
2017-08-29 01:10:04 +08:00
Alex Lam S.L
067d52b6ba harmony-v3.0.28 2017-08-20 01:19:06 +08:00
alexlamsl
e0e009ace2 Merge branch 'master' into harmony-v3.0.28 2017-08-20 00:35:46 +08:00
Alex Lam S.L
f81ff10a9b v3.0.28 2017-08-20 00:27:01 +08:00
kzc
ae0f117da6 Introduce new compress option unsafe_arrows (#2278)
* Not always safe to convert a function expression to an arrow
  function when code depends on the function prototype existing.

Fixes #2271
2017-08-16 22:51:26 +08:00
Alex Lam S.L
a5461e0adc prohibit let/const redeclaration (#2277)
fixes #2270
2017-08-14 12:31:12 +08:00
Erik Desjardins
16d40915b4 don't escape null characters as \0 when followed by any digit (#2273)
fixes #2272
2017-08-14 12:30:08 +08:00
Alex Lam S.L
2bf8216e50 fix pure_getters on spread of objects (#2275) 2017-08-13 22:08:33 +08:00
kzc
2ed3f8db44 fix output of spread of a sequence (#2268)
fixes #2267
2017-08-03 00:40:19 +08:00
kzc
4700c14855 implement object rest/spread (#2265)
- improve parse errors for destructuring spread elements
- `unsafe` for object literals with rest elements

Miscellaneous
- increase mocha unicode surrogate test timeout
2017-08-02 13:47:58 +08:00
Alex Lam S.L
e7c21e87e3 fix ie8 mangling of top-level AST_SymbolCatch (#2263)
fixes #2254
2017-08-01 02:38:32 +08:00
Alex Lam S.L
f54ab16843 harmony-v3.0.27 2017-07-30 15:15:29 +08:00
alexlamsl
69cb459c16 fix-ups for #2258 2017-07-30 04:26:21 +08:00
alexlamsl
1eae8f2dcc Merge branch 'master' into harmony 2017-07-30 01:57:34 +08:00
Alex Lam S.L
c4c2ef44d0 v3.0.27 2017-07-30 01:50:42 +08:00
Alex Lam S.L
a845897758 improve mangle.properties (#2261)
- include dead code when `keep_quoted`
- unify `keep_quoted` & `reserved`
- make `test/run-tests.js` consistent with `minify()`

fixes #2256
2017-07-29 23:02:04 +08:00
kzc
d600c78d7b have keep_quoted respect quoted method names (#2258)
fixes #2257
2017-07-28 19:42:12 +08:00
kzc
32ea2c5530 issue template: describe acceptable JS input (#2255) 2017-07-27 21:38:36 +08:00
Alex Lam S.L
d3df2f985d extend collapse_vars to let and const (#2252)
fixes #2250
2017-07-25 22:07:21 +08:00
Alex Lam S.L
69861824b5 enhance test for #2242 (#2248) 2017-07-24 00:32:33 +08:00
Alex Lam S.L
1e0c7d2bc5 harmony-v3.0.26 2017-07-23 16:54:46 +08:00
alexlamsl
98b850580b fix for #2242 on harmony 2017-07-23 16:20:53 +08:00
alexlamsl
29011ea60a remove ascii_identifiers 2017-07-23 12:54:50 +08:00
alexlamsl
77d18be073 Merge branch 'master' into harmony-v3.0.26 2017-07-23 12:53:13 +08:00
Alex Lam S.L
bc61deeca9 v3.0.26 2017-07-23 12:39:36 +08:00
Alex Lam S.L
6a5e74b44e unescape surrogate pairs only (#2246)
fixes #2242
2017-07-23 12:38:21 +08:00
Alex Lam S.L
54446341ee update dependencies (#2241)
- acorn@5.1.1
- commander@2.11.0
- mocha@3.4.2
2017-07-16 16:20:40 +08:00
Alex Lam S.L
91f8b57b3e harmony-v3.0.25 2017-07-16 12:21:39 +08:00
alexlamsl
3a2b737c42 Merge branch 'master' into harmony-v3.0.25 2017-07-16 11:15:07 +08:00
Alex Lam S.L
4e12a6f740 v3.0.25 2017-07-16 11:05:53 +08:00
Alex Lam S.L
b35dfc2599 reject malformed CLI parameters (#2239)
fixes #2237
2017-07-15 23:50:27 +08:00
Alex Lam S.L
9e1da9235e ensure ie8 works with mangled properties (#2238)
fixes #2234
2017-07-15 22:50:59 +08:00
Alex Lam S.L
a5ffe2c23f drop unused builtin globals under unsafe (#2236)
fixes #2233
2017-07-15 15:16:11 +08:00
Alex Lam S.L
9282e7b0c6 fix unsafe evaluate of Object static methods (#2232)
fixes #2231
2017-07-14 19:52:01 +08:00
Alex Lam S.L
5229cb2b1b drop unused compound assignments (#2230)
fixes #2226
2017-07-14 00:39:34 +08:00
Alex Lam S.L
458e3e15f0 enhance passes (#2229)
- remove hardcoded upper limit
- continue based on node count reduction
- emit verbose statistics

fixes #2226
2017-07-13 02:18:59 +08:00
Alex Lam S.L
c615a1e80a fix gzip stream in test/benchmark.js (#2228) 2017-07-12 02:55:57 +08:00
Alex Lam S.L
10a938cb79 enhance source mapping on IIFEs (#2224)
fixes #2213
2017-07-11 02:34:28 +08:00
kzc
0f4278148d uglify-es: update repository and project tagline (#2221) 2017-07-09 23:55:38 +08:00
Alex Lam S.L
4956ad311b benchmark gzipped output (#2220) 2017-07-09 01:44:59 +08:00
kzc
145874e504 docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 01:06:15 +08:00
kzc
f30375052b docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 00:48:53 +08:00
Alex Lam S.L
3e1a8598bf harmony-v3.0.24 2017-07-08 14:51:47 +08:00
alexlamsl
ef63de6968 handle AST_Arrow IIFEs in collapse_vars 2017-07-08 14:27:06 +08:00
alexlamsl
2539fb8096 inline property access of AST_ConciseMethod 2017-07-08 14:25:58 +08:00
alexlamsl
a556dd2dcb Merge branch 'master' into harmony-v3.0.24 2017-07-08 13:12:54 +08:00
Alex Lam S.L
bd7be07c38 v3.0.24 2017-07-08 12:53:20 +08:00
Alex Lam S.L
71ee91e716 handle duplicate argument names in collapse_vars (#2215) 2017-07-08 04:42:35 +08:00
kzc
e7334b4048 uglify-es: have repository point to harmony branch (#2212) 2017-07-07 11:39:48 +08:00
Alex Lam S.L
4f70d2e28c inlining of static methods & constants (#2211)
- guard by `unsafe`
- support `Array`, `Math`, `Number`, `Object` & `String`

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

fixes #2208
2017-07-06 21:51:58 +08:00
Alex Lam S.L
f5c46db738 improve AST_ConciseMethod compression (#2202)
p(){return x;} ---> p:()=>x

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

View File

@@ -8,7 +8,16 @@
**Uglify version (`uglifyjs -V`)**
**JavaScript input** <!-- ideally as small as possible -->
**JavaScript input**
<!--
A complete parsable JS program exhibiting the issue with
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
Issues without a reproducible test case will be closed.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.**

392
README.md
View File

@@ -1,7 +1,7 @@
uglify-es
=========
**uglify-es** is an ECMAScript parser, minifier, compressor and beautifier toolkit for ES6+.
A JavaScript parser, mangler/compressor and beautifier toolkit for ES6+.
#### Note:
- **`uglify-es` is API/CLI compatible with `uglify-js@3`.**
@@ -102,14 +102,20 @@ a double dash to prevent input files being used as option arguments:
sequences.
--config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions.
--ecma <version> Specifiy ECMAScript release: 5, 6, 7 or 8.
--ecma <version> Specify ECMAScript release: 5, 6, 7 or 8.
--ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options.
By default UglifyJS will not try to be IE-proof.
--keep-classnames Do not mangle/drop class names.
--keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name.
--name-cache <file> File to hold mangled name mappings.
--safari10 Support non-standard Safari 10/11.
Equivalent to setting `safari10: true` in `minify()`
for `mangle` and `output` options.
By default `uglify-es` will not work around
Safari 10/11 bugs.
--self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options:
`base` Path to compute relative paths from input files.
@@ -148,19 +154,19 @@ debugging your compressed JavaScript. To get a source map, pass
Additional options:
- `--source-map filename=<NAME>` to specify the name of the source map.
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
- `--source-map root=<URL>` to pass the URL where the original files can be found.
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
`//# sourceMappingURL=` directive.
- `--source-map url=<URL>` to specify the URL where the source map can be found.
For example:
uglifyjs js/file1.js js/file2.js \
-o foo.min.js -c -m \
--source-map root="http://foo.com/src",url=foo.min.js.map
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
The above will compress and mangle `file1.js` and `file2.js`, will drop the
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
@@ -179,8 +185,8 @@ CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →
compressed JS by mapping every token in the compiled JS to its original
location.
To use this feature pass `--source-map content="/path/to/input/source.map"`
or `--source-map content=inline` if the source map is included inline with
To use this feature pass `--source-map "content='/path/to/input/source.map'"`
or `--source-map "content=inline"` if the source map is included inline with
the sources.
## CLI compress options
@@ -201,17 +207,15 @@ Example:
To enable the mangler you need to pass `--mangle` (`-m`). The following
(comma-separated) options are supported:
- `toplevel` mangle names declared in the top level scope (disabled by
default).
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
- `eval` mangle names visible in scopes where `eval` or `with` are used
(disabled by default).
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
When mangling is enabled but you want to prevent certain names from being
mangled, you can declare those names with `--mangle reserved` — pass a
comma-separated list of names. For example:
uglifyjs ... -m reserved=[$,require,exports]
uglifyjs ... -m reserved=['$','require','exports']
to prevent the `require`, `exports` and `$` names from being changed.
@@ -221,7 +225,7 @@ to prevent the `require`, `exports` and `$` names from being changed.
is a separate step, different from variable name mangling. Pass
`--mangle-props` to enable it. It will mangle all properties in the
input code with the exception of built in DOM properties and properties
in core javascript classes. For example:
in core JavaScript classes. For example:
```javascript
// example.js
@@ -236,7 +240,7 @@ x.bar_ = 2;
x["baz_"] = 3;
console.log(x.calc());
```
Mangle all properties (except for javascript `builtins`):
Mangle all properties (except for JavaScript `builtins`):
```bash
$ uglifyjs example.js -c -m --mangle-props
```
@@ -511,6 +515,18 @@ if (result.error) throw result.error;
- `ie8` (default `false`) - set to `true` to support IE8.
- `keep_classnames` (default: `undefined`) - pass `true` to prevent discarding or mangling
of class names.
- `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
of function names. Useful for code relying on `Function.prototype.name`. If the
top level minify option `keep_classnames` is `undefined` it will be overriden with
the value of the top level minify option `keep_fnames`.
- `safari10` (default: `false`) - pass `true` to work around Safari 10/11 bugs in
loop scoping and `await`. See `safari10` options in [`mangle`](#mangle-options)
and [`output`](#output-options) for details.
## Minify options structure
```javascript
@@ -535,9 +551,12 @@ if (result.error) throw result.error;
// source map options
},
ecma: 5, // specify one of: 5, 6, 7 or 8
nameCache: null, // or specify a name cache object
toplevel: false,
keep_classnames: false,
keep_fnames: false,
ie8: false,
nameCache: null, // or specify a name cache object
safari10: false,
toplevel: false,
warnings: false,
}
```
@@ -592,114 +611,109 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Parse options
- `bare_returns` (default `false`) -- support top level `return` statements
- `ecma` (default: `8`) -- specify one of `5`, `6`, `7` or `8`. Note: this setting
is not presently enforced except for ES8 optional trailing commas in function
parameter lists and calls with `ecma` `8`.
- `html5_comments` (default `true`)
- `shebang` (default `true`) -- support `#!command` as the first line
## Compress options
- `sequences` (default: true) -- join consecutive simple statements using the
comma operator. May be set to a positive integer to specify the maximum number
of consecutive comma sequences that will be generated. If this option is set to
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
is grandfathered to be equivalent to `true` and as such means `200`. On rare
occasions the default sequences limit leads to very slow compress times in which
case a value of `20` or less is recommended.
- `arrows` (default: `true`) -- Converts `()=>{return x}` to `()=>x`. Class
and object literal methods will also be converted to arrow expressions if
the resultant code is shorter: `m(){return x}` becomes `m:()=>x`.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `properties` -- rewrite property access using the dot notation, for
example `foo["bar"] → foo.bar`
- `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c`
- `dead_code` -- remove unreachable code
- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables,
side effects permitting.
- `drop_debugger` -- remove `debugger;` statements
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
- `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to
allow improved compression. This might be unsafe when an at least one of two
operands is an object with computed values due the use of methods like `get`,
or `valueOf`. This could cause change in execution order after operands in the
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe_Func` (default: false) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
- `unsafe_math` (default: false) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_proto` (default: false) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
- `unsafe_regexp` (default: false) -- enable substitutions of variables with
`RegExp` values the same way as if they are constants.
- `conditionals` -- apply optimizations for `if`-s and conditional
expressions
- `comparisons` -- apply certain optimizations to binary nodes, for example:
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
e.g. `!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `evaluate` -- attempt to evaluate constant expressions
- `computed_props` (default: `true`) -- Transforms constant computed properties
into regular ones: `{["computed"]: 1}` is converted to `{computed: 1}`.
- `arrows` (default `true`) -- convert ES5 style anonymous function expressions
to arrow functions if permissible by language semantics.
Note: `arrows` requires that the `ecma` compress option is set to `6` or greater.
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
expressions
- `booleans` -- various optimizations for boolean context, for example `!!a
? b : c → a ? b : c`
- `dead_code` (default: `true`) -- remove unreachable code
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
statically determine the condition
- `drop_console` (default: `false`) -- Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `unused` -- drop unreferenced functions and variables (simple direct variable
assignments do not count as references unless set to `"keep_assign"`)
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
in the top level scope (`false` by default, `true` to drop both unreferenced
functions and variables)
- `ecma` (default: `5`) -- Pass `6` or greater to enable `compress` options that
will transform ES5 code into smaller ES6+ equivalent forms.
- `top_retain` -- prevent specific toplevel functions and variables from `unused`
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
- `hoist_funs` -- hoist function declarations
- `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_funs` (default: `false`) -- hoist function declarations
- `hoist_props` (default: `true`) -- hoist properties from constant object and
array literals into regular variables subject to a set of constraints. For example:
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
and the `compress` option `toplevel` enabled.
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
by default because it seems to increase the size of the output in general)
- `if_return` -- optimizations for if/return and if/continue
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
- `inline` -- embed simple functions
- `inline` (default: `true`) -- inline calls to function with simple/`return` statement:
- `false` -- same as `0`
- `0` -- disabled inlining
- `1` -- inline simple functions
- `2` -- inline functions with arguments
- `3` -- inline functions with arguments and variables
- `true` -- same as `3`
- `join_vars` -- join consecutive `var` statements
- `join_vars` (default: `true`) -- join consecutive `var` statements
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()`
- `keep_classnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding class names. See also: the `keep_classnames`
[mangle option](#mangle).
- `collapse_vars` -- Collapse single-use non-constant variables - side
effects permitting.
- `keep_fargs` (default: `true`) -- Prevents the compressor from discarding unused
function arguments. You need this for code which relies on `Function.length`.
- `reduce_vars` -- Improve optimization on variables assigned with and
used as constant values.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `warnings` -- display warnings when dropping unreachable code or unused
declarations etc.
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.
- `negate_iife` -- negate "Immediately-Called Function Expressions"
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
when we can statically determine the condition.
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the
code generator would insert.
- `pure_getters` -- the default is `false`. If you pass `true` for
this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`.
- `passes` (default: `1`) -- The maximum number of times to run compress.
In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time.
- `pure_funcs` -- default `null`. You can pass an array of names and
- `properties` (default: `true`) -- rewrite property access using the dot notation, for
example `foo["bar"] → foo.bar`
- `pure_funcs` (default: `null`) -- You can pass an array of names and
UglifyJS will assume that those functions do not produce side
effects. DANGER: will not check if the name is redefined in scope.
An example case here, for instance `var q = Math.floor(a/b)`. If
@@ -710,57 +724,111 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
statement would get discarded. The current implementation adds some
overhead (compression will be slower).
- `drop_console` -- default `false`. Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
`foo` is certain to not throw, i.e. not `null` or `undefined`.
- `expression` -- default `false`. Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
- `reduce_funcs` (default: `true`) -- Allows single-use functions to be
inlined as function expressions when permissible allowing further
optimization. Enabled by default. Option depends on `reduce_vars`
being enabled. Some code runs faster in the Chrome V8 engine if this
option is disabled. Does not negatively impact other major browsers.
- `keep_fargs` -- default `true`. Prevents the
compressor from discarding unused function arguments. You need this
for code which relies on `Function.length`.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values.
- `keep_fnames` -- default `false`. Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `sequences` (default: `true`) -- join consecutive simple statements using the
comma operator. May be set to a positive integer to specify the maximum number
of consecutive comma sequences that will be generated. If this option is set to
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
is grandfathered to be equivalent to `true` and as such means `200`. On rare
occasions the default sequences limit leads to very slow compress times in which
case a value of `20` or less is recommended.
- `passes` -- default `1`. Number of times to run compress with a maximum of 3.
In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time.
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
- `side_effects` (default: `true`) -- Pass `false` to disable potentially dropping
functions marked as "pure". A function call is marked as "pure" if a comment
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();`
- `ecma` -- default `5`. Pass `6` or greater to enable `compress` options that
will transform ES5 code into smaller ES6+ equivalent forms.
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
both unreferenced functions and variables)
- `top_retain` (default: `null`) -- prevent specific toplevel functions and
variables from `unused` removal (can be array, comma-separated, RegExp or
function. Implies `toplevel`)
- `typeofs` (default: `true`) -- Transforms `typeof foo == "undefined"` into
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
earlier versions due to known issues.
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
- `unsafe_arrows` (default: `false`) -- Convert ES5 style anonymous function
expressions to arrow functions if the function body does not reference `this`.
Note: it is not always safe to perform this conversion if code relies on the
the function having a `prototype`, which arrow functions lack.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
allow improved compression. This might be unsafe when an at least one of two
operands is an object with computed values due the use of methods like `get`,
or `valueOf`. This could cause change in execution order after operands in the
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
- `unsafe_math` (default: `false`) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_methods` (default: false) -- Converts `{ m: function(){} }` to
`{ m(){} }`. `ecma` must be set to `6` or greater to enable this transform.
If `unsafe_methods` is a RegExp then key/value pairs with keys matching the
RegExp will be converted to concise methods.
Note: if enabled there is a risk of getting a "`<method name>` is not a
constructor" TypeError should any code try to `new` the former function.
- `unsafe_proto` (default: `false`) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
`RegExp` values the same way as if they are constants.
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`)
- `warnings` (default: `false`) -- display warnings when dropping unreachable
code or unused declarations etc.
## Mangle options
- `reserved` (default `[]`). Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`.
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
top level scope.
- `keep_classnames` (default `false`) -- Pass `true` to not mangle class names.
See also: the `keep_classnames` [compress option](#compress-options).
- `keep_classnames` (default `false`). Pass `true` to not mangle class names.
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
- `keep_fnames` (default `false`) -- Pass `true` to not mangle function names.
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
[compress option](#compress-options).
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `reserved` (default `[]`) -- Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`.
- `safari10` (default `false`). Pass `true` to work around the Safari 10 loop
- `toplevel` (default `false`) -- Pass `true` to mangle names declared in the
top level scope.
- `safari10` (default `false`) -- Pass `true` to work around the Safari 10 loop
iterator [bug](https://bugs.webkit.org/show_bug.cgi?id=171041)
"Cannot declare a let variable twice".
See also: the `safari10` [output option](#output-options).
Examples:
@@ -786,16 +854,20 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
### Mangle properties options
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
`reserved` array.
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
names matching the regular expression.
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
- `debug` (default: `false`) -— Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
DOM properties. Not recommended to override this setting.
- `debug` (default: `false`) -— Mangle names with the original name still present.
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
names matching the regular expression.
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
`reserved` array.
## Output options
The code generator tries to output shortest code possible by default. In
@@ -804,37 +876,50 @@ can pass additional arguments that control the code output:
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
regexps (affects directives with non-ascii characters becoming invalid)
- `beautify` (default `true`) -- whether to actually beautify the output.
Passing `-b` will set this to true, but you might need to pass `-b` even
when you want to generate minified code, in order to specify additional
arguments, so you can use `-b beautify=false` to override it.
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
`do`, `while` or `with` statements, even if their body is a single
statement.
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
comments, `"some"` to preserve some comments, a regular expression string
(e.g. `/^!/`) or a function.
- `ecma` (default `5`) -- set output printing mode. Set `ecma` to `6` or
greater to emit shorthand object properties - i.e.: `{a}` instead of `{a: a}`.
The `ecma` option will only change the output in direct control of the
beautifier. Non-compatible features in the abstract syntax tree will still
be output as is. For example: an `ecma` setting of `5` will **not** convert
ES6+ code to ES5.
- `indent_level` (default 4)
- `indent_start` (default 0) -- prefix all lines by that many spaces
- `indent_level` (default `4`)
- `indent_start` (default `0`) -- prefix all lines by that many spaces
- `inline_script` (default `false`) -- escape the slash in occurrences of
`</script` in strings
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
quotes from property names in object literals.
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
- `preamble` (default `null`) -- when passed it must be a string and
it will be prepended to the output literally. The source map will
adjust for this text. Can be used to insert a comment containing
licensing information, for example.
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
only works if `beautify` is set to `false`.
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
objects
- `quote_style` (default `0`) -- preferred quote style for strings (affects
quoted property names and directives as well):
- `0` -- prefers double quotes, switches to single quotes when there are
@@ -842,16 +927,27 @@ can pass additional arguments that control the code output:
- `1` -- always use single quotes
- `2` -- always use double quotes
- `3` -- always use the original quotes
- `safari10` (default `false`) -- set this option to `true` to work around
the [Safari 10/11 await bug](https://bugs.webkit.org/show_bug.cgi?id=176685).
See also: the `safari10` [mangle option](#mangle-options).
- `semicolons` (default `true`) -- separate statements with semicolons. If
you pass `false` then whenever possible we will use a newline instead of a
semicolon, leading to more readable output of uglified code (size before
gzip could be smaller; size after gzip insignificantly larger).
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
- `width` (default 80) -- only takes effect when beautification is on, this
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
PhantomJS users should set this option to `true`.
- `width` (default `80`) -- only takes effect when beautification is on, this
specifies an (orientative) line width that the beautifier will try to
obey. It refers to the width of the line text (excluding indentation).
It doesn't work very well currently, but it does make the code generated
by UglifyJS more readable.
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
function expressions. See
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
@@ -897,7 +993,6 @@ when this flag is on:
- `new Object()``{}`
- `String(exp)` or `exp.toString()``"" + exp`
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
- `typeof foo == "undefined"` → `foo === void 0`
- `void 0``undefined` (if there is a variable named "undefined" in
scope; we do it because the variable name will be mangled, typically
reduced to a single character)
@@ -1050,3 +1145,30 @@ in total it's a bit more than just using UglifyJS's own parser.
[acorn]: https://github.com/ternjs/acorn
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
### Uglify Fast Minify Mode
It's not well known, but whitespace removal and symbol mangling accounts
for 95% of the size reduction in minified code for most JavaScript - not
elaborate code transforms. One can simply disable `compress` to speed up
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
comparable minify speeds and gzip sizes to
[`butternut`](https://www.npmjs.com/package/butternut):
| d3.js | minify size | gzip size | minify time (seconds) |
| --- | ---: | ---: | ---: |
| original | 451,131 | 108,733 | - |
| uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
| uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
| butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
| uglify-js@3.0.24 mangle=true, compress=true | 212,511 | 71,560 | 3.36 |
| babili@0.1.4 | 210,713 | 72,140 | 12.64 |
To enable fast minify mode from the CLI use:
```
uglifyjs file.js -m
```
To enable fast minify mode with the API use:
```js
UglifyJS.minify(code, { compress: false, mangle: true });
```

View File

@@ -1,24 +1,20 @@
environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4.0"
- nodejs_version: "6.0"
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4"
- nodejs_version: "6"
- nodejs_version: "8"
install:
- ps: Install-Product node $env:nodejs_version
- set UGLIFYJS_TEST_ALL=1
- npm install
build: off
cache:
- tmp
matrix:
fast_finish: true
platform:
- x86
- x64
install:
- ps: Install-Product node $env:nodejs_version $env:platform
- npm install
test_script:
- node --version
- npm --version
- npm test
build: off

View File

@@ -3,11 +3,7 @@
"use strict";
// workaround for tty output truncation upon process.exit()
[process.stdout, process.stderr].forEach(function(stream){
if (stream._handle && stream._handle.setBlocking)
stream._handle.setBlocking(true);
});
require("../tools/exit");
var fs = require("fs");
var info = require("../package.json");
@@ -15,7 +11,7 @@ var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var files = {};
var options = {
compress: false,
@@ -35,19 +31,22 @@ else if (process.argv.indexOf("options") >= 0) program.helpInformation = functio
}
return text.join("\n");
};
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js("mangle-props", true));
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js("beautify", true));
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("--ecma <version>", "Specifiy ECMAScript release: 5, 6, 7 or 8.");
program.option("--ecma <version>", "Specify ECMAScript release: 5, 6, 7 or 8.");
program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-classnames", "Do not mangle/drop class names.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--safari10", "Support non-standard Safari 10.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.")
@@ -66,11 +65,14 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
"compress",
"ie8",
"mangle",
"rename",
"safari10",
"sourceMap",
"toplevel",
"wrap"
].forEach(function(name) {
if (name in program) {
if (name == "rename" && program[name]) return;
options[name] = program[name];
}
});
@@ -95,6 +97,9 @@ if (program.define) {
options.compress.global_defs[expr] = program.define[expr];
}
}
if (program.keepClassnames) {
options.keep_classnames = true;
}
if (program.keepFnames) {
options.keep_fnames = true;
}
@@ -315,7 +320,7 @@ function read_file(path, default_value) {
}
}
function parse_js(flag, constants) {
function parse_js(flag) {
return function(value, options) {
options = options || {};
try {
@@ -333,7 +338,7 @@ function parse_js(flag, constants) {
if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string();
var value = node.right;
if (!constants) {
if (flag) {
options[name] = value;
} else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string);
@@ -356,14 +361,18 @@ function parse_js(flag, constants) {
}
}));
} catch(ex) {
options[value] = null;
if (flag) {
fatal("Error parsing arguments for '" + flag + "': " + value);
} else {
options[value] = null;
}
}
return options;
}
}
function parse_source_map() {
var parse = parse_js("sourceMap", true);
var parse = parse_js();
return function(value, options) {
var hasContent = options && "content" in options;
var settings = parse(value, options);

View File

@@ -87,7 +87,7 @@ function DEFNODE(type, props, methods, base) {
return ctor;
};
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", {
}, null);
var AST_Node = DEFNODE("Node", "start end", {
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value scope quote", {
var AST_Directive = DEFNODE("Directive", "value quote", {
$documentation: "Represents a directive, like \"use strict\";",
$propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character"
},
}, AST_Statement);
@@ -303,10 +302,9 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
@@ -315,9 +313,9 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
},
get_defun_scope: function () {
get_defun_scope: function() {
var self = this;
while (self.is_block_scope() && self.parent_scope) {
while (self.is_block_scope()) {
self = self.parent_scope;
}
return self;
@@ -391,15 +389,15 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda);
var AST_Function = DEFNODE("Function", null, {
var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Arrow = DEFNODE("Arrow", null, {
var AST_Arrow = DEFNODE("Arrow", "inlined", {
$documentation: "An ES6 Arrow function ((a) => b)"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
var AST_Defun = DEFNODE("Defun", "inlined", {
$documentation: "A function definition"
}, AST_Lambda);
@@ -450,10 +448,8 @@ var AST_TemplateString = DEFNODE("TemplateString", "segments", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.segments.forEach(function(seg, i){
if (i % 2 !== 0) {
seg._walk(visitor);
}
this.segments.forEach(function(seg){
seg._walk(visitor);
});
});
}
@@ -697,7 +693,7 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable",
name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
@@ -912,7 +908,7 @@ var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator asyn
$documentation: "An ES6 concise method inside an object or class"
}, AST_ObjectProperty);
var AST_Class = DEFNODE("Class", "name extends properties", {
var AST_Class = DEFNODE("Class", "name extends properties inlined", {
$propdoc: {
name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
extends: "[AST_Node]? optional parent class",
@@ -1044,7 +1040,7 @@ var AST_This = DEFNODE("This", null, {
var AST_Super = DEFNODE("Super", null, {
$documentation: "The `super` symbol",
}, AST_Symbol);
}, AST_This);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
@@ -1160,7 +1156,7 @@ TreeWalker.prototype = {
if (!ret && descend) {
descend.call(node);
}
this.pop(node);
this.pop();
return ret;
},
parent: function(n) {
@@ -1179,8 +1175,8 @@ TreeWalker.prototype = {
}
this.stack.push(node);
},
pop: function(node) {
this.stack.pop();
pop: function() {
var node = this.stack.pop();
if (node instanceof AST_Lambda || node instanceof AST_Class) {
this.directives = Object.getPrototypeOf(this.directives);
}
@@ -1207,24 +1203,6 @@ TreeWalker.prototype = {
}
}
},
in_boolean_context: function() {
var stack = this.stack;
var i = stack.length, self = stack[--i];
while (i > 0) {
var p = stack[--i];
if ((p instanceof AST_If && p.condition === self) ||
(p instanceof AST_Conditional && p.condition === self) ||
(p instanceof AST_DWLoop && p.condition === self) ||
(p instanceof AST_For && p.condition === self) ||
(p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
{
return true;
}
if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
return false;
self = p;
}
},
loopcontrol_target: function(node) {
var stack = this.stack;
if (node.label) for (var i = stack.length; --i >= 0;) {

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,6 @@ function set_shorthand(name, options, keys) {
function init_cache(cache) {
if (!cache) return;
if (!("cname" in cache)) cache.cname = -1;
if (!("props" in cache)) {
cache.props = new Dictionary();
} else if (!(cache.props instanceof Dictionary)) {
@@ -39,7 +38,6 @@ function init_cache(cache) {
function to_json(cache) {
return {
cname: cache.cname,
props: cache.props.toObject()
};
}
@@ -51,11 +49,14 @@ function minify(files, options) {
compress: {},
ecma: undefined,
ie8: false,
keep_classnames: undefined,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
rename: undefined,
safari10: false,
sourceMap: false,
timings: false,
toplevel: false,
@@ -65,11 +66,20 @@ function minify(files, options) {
var timings = options.timings && {
start: Date.now()
};
if (options.keep_classnames === undefined) {
options.keep_classnames = options.keep_fnames;
}
if (options.rename === undefined) {
options.rename = options.compress && options.mangle;
}
set_shorthand("ecma", options, [ "parse", "compress", "output" ]);
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_classnames", options, [ "compress", "mangle" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("safari10", options, [ "mangle", "output" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
@@ -82,11 +92,16 @@ function minify(files, options) {
safari10: false,
toplevel: false,
}, true);
if (options.nameCache && options.mangle.properties) {
if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
options.mangle.properties = {};
}
if (!("cache" in options.mangle.properties)) {
if (options.mangle.properties.keep_quoted) {
quoted_props = options.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
options.mangle.properties.reserved = quoted_props;
}
if (options.nameCache && !("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {};
}
}
@@ -129,14 +144,20 @@ function minify(files, options) {
}
toplevel = options.parse.toplevel;
}
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
}
if (timings) timings.scope1 = Date.now();
if (options.compress) toplevel.figure_out_scope(options.mangle);
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 (timings) timings.scope2 = Date.now();
if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
@@ -194,9 +215,10 @@ function minify(files, options) {
if (timings) {
timings.end = Date.now();
result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2),
compress: 1e-3 * (timings.scope2 - timings.compress),
parse: 1e-3 * (timings.rename - timings.parse),
rename: 1e-3 * (timings.compress - timings.rename),
compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),

View File

@@ -52,9 +52,9 @@ function is_some_comments(comment) {
function OutputStream(options) {
var readonly = !options;
options = defaults(options, {
ascii_only : false,
ascii_identifiers: undefined,
beautify : false,
bracketize : false,
comments : false,
@@ -69,6 +69,7 @@ function OutputStream(options) {
preserve_line : false,
quote_keys : false,
quote_style : 0,
safari10 : false,
semicolons : true,
shebang : true,
shorthand : undefined,
@@ -78,9 +79,6 @@ function OutputStream(options) {
wrap_iife : false,
}, true);
if (typeof options.ascii_identifiers === 'undefined')
options.ascii_identifiers = options.ascii_only;
if (options.shorthand === undefined)
options.shorthand = options.ecma > 5;
@@ -118,20 +116,16 @@ function OutputStream(options) {
var current_pos = 0;
var OUTPUT = "";
function to_ascii(str, identifier) {
return str.replace(/[\ud800-\udbff][\udc00-\udfff]|[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = get_full_char_code(ch, 0).toString(16);
if ((identifier && code.length === 1 && options.ecma >= 6) || code.length > 4) {
if (options.ecma < 6) {
if (identifier) {
return ch; // no \u{} support
}
return "\\u" + ch.charCodeAt(0).toString(16) + "\\u"
+ ch.charCodeAt(1).toString(16);
}
var to_utf8 = options.ascii_only ? function(str, identifier) {
if (options.ecma >= 6) {
str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
var code = get_full_char_code(ch, 0).toString(16);
return "\\u{" + code + "}";
} else if (code.length <= 2 && !identifier) {
});
}
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) {
while (code.length < 2) code = "0" + code;
return "\\x" + code;
} else {
@@ -139,6 +133,17 @@ function OutputStream(options) {
return "\\u" + code;
}
});
} : function(str) {
var s = "";
for (var i = 0, len = str.length; i < len; i++) {
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
s += "\\u" + str.charCodeAt(i).toString(16);
} else {
s += str[i];
}
}
return s;
};
function make_string(str, quote) {
@@ -159,7 +164,7 @@ function OutputStream(options) {
case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff";
case "\0":
return /[0-7]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
}
return s;
});
@@ -172,7 +177,7 @@ function OutputStream(options) {
function quote_template() {
return '`' + str.replace(/`/g, '\\`') + '`';
}
if (options.ascii_only) str = to_ascii(str);
str = to_utf8(str);
if (quote === "`") return quote_template();
switch (options.quote_style) {
case 1:
@@ -198,8 +203,7 @@ function OutputStream(options) {
function make_name(name) {
name = name.toString();
if (options.ascii_identifiers)
name = to_ascii(name, true);
name = to_utf8(name, true);
return name;
};
@@ -212,6 +216,9 @@ function OutputStream(options) {
var might_need_space = false;
var might_need_semicolon = false;
var might_add_newline = 0;
var need_newline_indented = false;
var need_space = false;
var newline_insert = -1;
var last = "";
var mapping_token, mapping_name, mappings = options.source_map && [];
@@ -265,12 +272,27 @@ function OutputStream(options) {
}
} : noop;
var requireSemicolonChars = makePredicate("( [ + * / - , .");
var requireSemicolonChars = makePredicate("( [ + * / - , . `");
function print(str) {
str = String(str);
var ch = get_full_char(str, 0);
var prev = get_full_char(last, last.length - 1);
if (need_newline_indented && ch) {
need_newline_indented = false;
if (ch != "\n") {
print("\n");
indent();
}
}
if (need_space && ch) {
need_space = false;
if (!/[\s;})]/.test(ch)) {
space();
}
}
newline_insert = -1;
var prev = last.charAt(last.length - 1);
if (might_need_semicolon) {
might_need_semicolon = false;
@@ -372,7 +394,13 @@ function OutputStream(options) {
} : function(col, cont) { return cont() };
var newline = options.beautify ? function() {
print("\n");
if (newline_insert < 0) return print("\n");
if (OUTPUT[newline_insert] != "\n") {
OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert);
current_pos++;
current_line++;
}
newline_insert++;
} : options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
@@ -444,6 +472,122 @@ function OutputStream(options) {
return OUTPUT;
};
function prepend_comments(node) {
var self = this;
var start = node.start;
if (!start) return;
if (!(start.comments_before && start.comments_before._dumped === self)) {
var comments = start.comments_before;
if (!comments) {
comments = start.comments_before = [];
}
comments._dumped = self;
if (node instanceof AST_Exit && node.value) {
var tw = new TreeWalker(function(node) {
var parent = tw.parent();
if (parent instanceof AST_Exit
|| parent instanceof AST_Binary && parent.left === node
|| parent.TYPE == "Call" && parent.expression === node
|| parent instanceof AST_Conditional && parent.condition === node
|| parent instanceof AST_Dot && parent.expression === node
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) {
if (!node.start) return;
var text = node.start.comments_before;
if (text && text._dumped !== self) {
text._dumped = self;
comments = comments.concat(text);
}
} else {
return true;
}
});
tw.push(node);
node.value.walk(tw);
}
if (current_pos == 0) {
if (comments.length > 0 && options.shebang && comments[0].type == "comment5") {
print("#!" + comments.shift().value + "\n");
indent();
}
var preamble = options.preamble;
if (preamble) {
print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(comment_filter, node);
if (comments.length == 0) return;
var last_nlb = /(^|\n) *$/.test(OUTPUT);
comments.forEach(function(c, i) {
if (!last_nlb) {
if (c.nlb) {
print("\n");
indent();
last_nlb = true;
} else if (i > 0) {
space();
}
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
indent();
last_nlb = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
last_nlb = false;
}
});
if (!last_nlb) {
if (start.nlb) {
print("\n");
indent();
} else {
space();
}
}
}
}
function append_comments(node, tail) {
var self = this;
var token = node.end;
if (!token) return;
var comments = token[tail ? "comments_before" : "comments_after"];
if (comments
&& comments._dumped !== self
&& (node instanceof AST_Statement || all(comments, function(c) {
return !/comment[134]/.test(c.type);
}))) {
comments._dumped = self;
var insert = OUTPUT.length;
comments.filter(comment_filter, node).forEach(function(c, i) {
need_space = false;
if (need_newline_indented) {
print("\n");
indent();
need_newline_indented = false;
} else if (c.nlb && (i > 0 || !/(^|\n) *$/.test(OUTPUT))) {
print("\n");
indent();
} else if (i > 0 || !tail) {
space();
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
need_newline_indented = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
need_space = true;
}
});
if (OUTPUT.length > insert) newline_insert = insert;
}
}
var stack = [];
return {
get : get,
@@ -461,7 +605,7 @@ function OutputStream(options) {
last : function() { return last },
semicolon : semicolon,
force_semicolon : force_semicolon,
to_ascii : to_ascii,
to_utf8 : to_utf8,
print_name : function(name) { print(make_name(name)) },
print_string : function(str, quote, escape_directive) {
var encoded = encode_string(str, quote);
@@ -486,7 +630,8 @@ function OutputStream(options) {
with_square : with_square,
add_mapping : add_mapping,
option : function(opt) { return options[opt] },
comment_filter : comment_filter,
prepend_comments: readonly ? noop : prepend_comments,
append_comments : readonly || comment_filter === return_false ? noop : append_comments,
line : function() { return current_line },
col : function() { return current_col },
pos : function() { return current_pos },
@@ -509,18 +654,23 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator);
};
var use_asm = false;
var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen, prev_use_asm = use_asm;
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
use_asm = true;
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
}
function doit() {
self.add_comments(stream);
stream.prepend_comments(self);
self.add_source_map(stream);
generator(self, stream);
stream.append_comments(self);
}
stream.push_node(self);
if (force_parens || self.needs_parens(stream)) {
@@ -529,85 +679,18 @@ function OutputStream(options) {
doit();
}
stream.pop_node();
if (self instanceof AST_Scope) {
use_asm = prev_use_asm;
if (self === use_asm) {
use_asm = null;
}
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
AST_Node.DEFMETHOD("print_to_string", function(options){
var s = OutputStream(options);
if (!options) s._readonly = true;
this.print(s);
return s.get();
});
/* -----[ comments ]----- */
AST_Node.DEFMETHOD("add_comments", function(output){
if (output._readonly) return;
var self = this;
var start = self.start;
if (start && !start._comments_dumped) {
start._comments_dumped = true;
var comments = start.comments_before || [];
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
// and https://github.com/mishoo/UglifyJS2/issues/372
if (self instanceof AST_Exit && self.value) {
self.value.walk(new TreeWalker(function(node){
if (node.start && node.start.comments_before) {
comments = comments.concat(node.start.comments_before);
node.start.comments_before = [];
}
if (node instanceof AST_Function ||
node instanceof AST_Array ||
node instanceof AST_Object)
{
return true; // don't go inside.
}
}));
}
if (output.pos() == 0) {
if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") {
output.print("#!" + comments.shift().value + "\n");
output.indent();
}
var preamble = output.option("preamble");
if (preamble) {
output.print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(output.comment_filter, self);
// Keep single line comments after nlb, after nlb
if (!output.option("beautify") && comments.length > 0 &&
/comment[134]/.test(comments[0].type) &&
output.col() !== 0 && comments[0].nlb)
{
output.print("\n");
}
comments.forEach(function(c){
if (/comment[134]/.test(c.type)) {
output.print("//" + c.value + "\n");
output.indent();
}
else if (c.type == "comment2") {
output.print("/*" + c.value + "*/");
if (start.nlb) {
output.print("\n");
output.indent();
} else {
output.space();
}
}
});
}
});
/* -----[ PARENTHESES ]----- */
function PARENS(nodetype, func) {
@@ -620,9 +703,7 @@ function OutputStream(options) {
}
};
PARENS(AST_Node, function(){
return false;
});
PARENS(AST_Node, return_false);
// a function expression needs parens around it when it's provably
// the first token to appear in a statement.
@@ -651,15 +732,9 @@ function OutputStream(options) {
return p instanceof AST_PropAccess && p.expression === this;
});
PARENS(AST_ClassExpression, function(output){
return output.parent() instanceof AST_SimpleStatement;
});
// same goes for an object literal, because otherwise it would be
// interpreted as a block of code.
PARENS(AST_Object, function(output){
return first_in_statement(output);
});
PARENS([ AST_ClassExpression, AST_Object ], first_in_statement);
PARENS(AST_Unary, function(output){
var p = output.parent();
@@ -676,7 +751,8 @@ function OutputStream(options) {
PARENS(AST_Await, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this;
|| p instanceof AST_Call && p.expression === this
|| output.option("safari10") && p instanceof AST_UnaryPrefix;
});
PARENS(AST_Sequence, function(output){
@@ -692,6 +768,7 @@ function OutputStream(options) {
* ==> 20 (side effect, set a := 10 and b := 20) */
|| p instanceof AST_Arrow // x => (x, x)
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
|| p instanceof AST_Expansion // [...(a, b)]
;
});
@@ -724,6 +801,10 @@ function OutputStream(options) {
// a = yield 3
if (p instanceof AST_Binary && p.operator !== "=")
return true;
// (yield 1)()
// new (yield 1)()
if (p instanceof AST_Call && p.expression === this)
return true;
// (yield 1) ? yield 2 : yield 3
if (p instanceof AST_Conditional && p.condition === this)
return true;
@@ -745,14 +826,15 @@ function OutputStream(options) {
// parens around it too, otherwise the call will be
// interpreted as passing the arguments to the upper New
// expression.
try {
this.walk(new TreeWalker(function(node){
if (node instanceof AST_Call) throw p;
}));
} catch(ex) {
if (ex !== p) throw ex;
return true;
}
var parens = false;
this.walk(new TreeWalker(function(node) {
if (parens || node instanceof AST_Scope) return true;
if (node instanceof AST_Call) {
parens = true;
return true;
}
}));
return parens;
}
});
@@ -892,14 +974,21 @@ function OutputStream(options) {
self.body.print(output);
output.semicolon();
});
function print_bracketed(body, output, allow_directives) {
if (body.length > 0) output.with_block(function(){
display_body(body, false, output, allow_directives);
});
else output.print("{}");
function print_bracketed(self, output, allow_directives) {
if (self.body.length > 0) {
output.with_block(function() {
display_body(self.body, false, output, allow_directives);
});
} else {
output.print("{");
output.with_indent(output.next_indent(), function() {
output.append_comments(self, true);
});
output.print("}");
}
};
DEFPRINT(AST_BlockStatement, function(self, output){
print_bracketed(self.body, output);
print_bracketed(self, output);
});
DEFPRINT(AST_EmptyStatement, function(self, output){
output.semicolon();
@@ -1011,7 +1100,7 @@ function OutputStream(options) {
});
});
output.space();
print_bracketed(self.body, output, true);
print_bracketed(self, output, true);
});
DEFPRINT(AST_Lambda, function(self, output){
self._do_print(output);
@@ -1066,7 +1155,7 @@ function OutputStream(options) {
if (self.body instanceof AST_Node) {
self.body.print(output);
} else {
print_bracketed(self.body, output);
print_bracketed(self, output);
}
if (needs_parens) { output.print(")") }
});
@@ -1223,7 +1312,7 @@ function OutputStream(options) {
DEFPRINT(AST_Try, function(self, output){
output.print("try");
output.space();
print_bracketed(self.body, output);
print_bracketed(self, output);
if (self.bcatch) {
output.space();
self.bcatch.print(output);
@@ -1240,12 +1329,12 @@ function OutputStream(options) {
self.argname.print(output);
});
output.space();
print_bracketed(self.body, output);
print_bracketed(self, output);
});
DEFPRINT(AST_Finally, function(self, output){
output.print("finally");
output.space();
print_bracketed(self.body, output);
print_bracketed(self, output);
});
/* -----[ var/const ]----- */
@@ -1358,6 +1447,7 @@ function OutputStream(options) {
self.exported_value.print(output);
} else if (self.exported_definition) {
self.exported_definition.print(output);
if (self.exported_definition instanceof AST_Definitions) return;
}
if (self.module_name) {
output.space();
@@ -1369,19 +1459,17 @@ function OutputStream(options) {
});
function parenthesize_for_noin(node, output, noin) {
if (!noin) node.print(output);
else try {
// need to take some precautions here:
// https://github.com/mishoo/UglifyJS2/issues/60
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Binary && node.operator == "in")
throw output;
}));
node.print(output);
} catch(ex) {
if (ex !== output) throw ex;
node.print(output, true);
}
var parens = false;
// need to take some precautions here:
// https://github.com/mishoo/UglifyJS2/issues/60
if (noin) node.walk(new TreeWalker(function(node) {
if (parens || node instanceof AST_Scope) return true;
if (node instanceof AST_Binary && node.operator == "in") {
parens = true;
return true;
}
}));
node.print(output, parens);
};
DEFPRINT(AST_VarDef, function(self, output){
@@ -1401,6 +1489,9 @@ function OutputStream(options) {
self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output))
return;
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function(){
self.args.forEach(function(expr, i){
if (i) output.comma();
@@ -1440,15 +1531,23 @@ function OutputStream(options) {
DEFPRINT(AST_Dot, function(self, output){
var expr = self.expression;
expr.print(output);
if (expr instanceof AST_Number && expr.getValue() >= 0) {
if (!/[xa-f.)]/i.test(output.last())) {
output.print(".");
var prop = self.property;
if (output.option("ie8") && RESERVED_WORDS(prop)) {
output.print("[");
output.add_mapping(self.end);
output.print_string(prop);
output.print("]");
} else {
if (expr instanceof AST_Number && expr.getValue() >= 0) {
if (!/[xa-f.)]/i.test(output.last())) {
output.print(".");
}
}
output.print(".");
// the name after dot would be mapped about here.
output.add_mapping(self.end);
output.print_name(prop);
}
output.print(".");
// the name after dot would be mapped about here.
output.add_mapping(self.end);
output.print_name(self.property);
});
DEFPRINT(AST_Sub, function(self, output){
self.expression.print(output);
@@ -1611,7 +1710,8 @@ function OutputStream(options) {
if (allowShortHand &&
self.value instanceof AST_Symbol &&
is_identifier_string(self.key) &&
get_name(self.value) === self.key
get_name(self.value) === self.key &&
is_identifier(self.key)
) {
print_property_name(self.key, self.quote, output);
@@ -1673,9 +1773,6 @@ function OutputStream(options) {
DEFPRINT(AST_Symbol, function (self, output) {
self._do_print(output);
});
DEFPRINT(AST_SymbolDeclaration, function(self, output){
self._do_print(output);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output){
output.print("this");
@@ -1703,9 +1800,7 @@ function OutputStream(options) {
if (regexp.raw_source) {
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
}
if (output.option("ascii_only")) {
str = output.to_ascii(str);
}
str = output.to_utf8(str);
output.print(str);
var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)

View File

@@ -44,9 +44,9 @@
"use strict";
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof new return switch throw try typeof var let void while with import';
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with';
var KEYWORDS_ATOM = 'false null true';
var RESERVED_WORDS = 'enum implements interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
var RESERVED_WORDS = 'enum implements import interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case yield await';
KEYWORDS = makePredicate(KEYWORDS);
@@ -365,11 +365,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
if (!is_comment) {
ret.comments_before = S.comments_before;
S.comments_before = [];
// make note of any newlines in the comments that came before
for (var i = 0, len = ret.comments_before.length; i < len; i++) {
ret.nlb = ret.nlb || ret.comments_before[i].nlb;
}
ret.comments_after = S.comments_before = [];
}
S.newline_before = false;
return new AST_Token(ret);
@@ -938,10 +934,15 @@ function parse($TEXT, options) {
function expect(punc) { return expect_token("punc", punc); };
function has_newline_before(token) {
return token.nlb || !all(token.comments_before, function(comment) {
return !comment.nlb;
});
}
function can_insert_semicolon() {
return !options.strict && (
S.token.nlb || is("eof") || is("punc", "}")
);
return !options.strict
&& (is("eof") || is("punc", "}") || has_newline_before(S.token));
};
function is_in_generator() {
@@ -982,17 +983,17 @@ function parse($TEXT, options) {
}
};
var statement = embed_tokens(function() {
var statement = embed_tokens(function(is_export_default) {
handle_regexp();
switch (S.token.type) {
case "string":
if (S.in_directives) {
var token = peek();
if (S.token.raw.indexOf("\\") == -1
&& (token.nlb
|| is_token(token, "eof")
|| is_token(token, "punc", ";")
|| is_token(token, "punc", "}"))) {
&& (is_token(token, "punc", ";")
|| is_token(token, "punc", "}")
|| has_newline_before(token)
|| is_token(token, "eof"))) {
S.input.add_directive(S.token.value);
} else {
S.in_directives = false;
@@ -1011,7 +1012,13 @@ function parse($TEXT, options) {
if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
next();
next();
return function_(AST_Defun, false, true);
return function_(AST_Defun, false, true, is_export_default);
}
if (S.token.value == "import" && !is_token(peek(), "punc", "(")) {
next();
var node = import_();
semicolon();
return node;
}
return is_token(peek(), "punc", ":")
? labeled_statement()
@@ -1079,7 +1086,7 @@ function parse($TEXT, options) {
case "function":
next();
return function_(AST_Defun);
return function_(AST_Defun, false, false, is_export_default);
case "if":
next();
@@ -1109,7 +1116,7 @@ function parse($TEXT, options) {
case "throw":
next();
if (S.token.nlb)
if (has_newline_before(S.token))
croak("Illegal newline after 'throw'");
var value = expression(true);
semicolon();
@@ -1149,15 +1156,11 @@ function parse($TEXT, options) {
body : statement()
});
case "import":
next();
var node = import_();
semicolon();
return node;
case "export":
next();
return export_();
if (!is_token(peek(), "punc", "(")) {
next();
return export_();
}
}
}
unexpected();
@@ -1165,10 +1168,6 @@ function parse($TEXT, options) {
function labeled_statement() {
var label = as_symbol(AST_Label);
if (label.name === "yield" && is_in_generator()) {
// Ecma-262, 12.1.1 Static Semantics: Early Errors
token_error(S.prev, "Yield cannot be used as label inside generators");
}
if (label.name === "await" && is_in_async()) {
token_error(S.prev, "await cannot be used as label inside async function");
}
@@ -1289,7 +1288,7 @@ function parse($TEXT, options) {
};
var arrow_function = function(start, argnames, is_async) {
if (S.token.nlb) {
if (has_newline_before(S.token)) {
croak("Unexpected newline before arrow (=>)");
}
@@ -1306,9 +1305,9 @@ function parse($TEXT, options) {
});
};
var function_ = function(ctor, is_generator_property, is_async) {
var function_ = function(ctor, is_generator_property, is_async, is_export_default) {
if (is_generator_property && is_async) croak("generators cannot be async");
var start = S.token
var start = S.token;
var in_statement = ctor === AST_Defun;
var is_generator = is("operator", "*");
@@ -1317,10 +1316,18 @@ function parse($TEXT, options) {
}
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
if (in_statement && !name)
unexpected();
if (in_statement && !name) {
if (is_export_default) {
ctor = AST_Function;
} else {
unexpected();
}
}
var args = parameters();
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
unexpected(prev());
var args = [];
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
return new ctor({
start : args.start,
@@ -1391,9 +1398,8 @@ function parse($TEXT, options) {
return tracker;
}
function parameters() {
function parameters(params) {
var start = S.token;
var params = [];
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
expect("(");
@@ -1413,7 +1419,6 @@ function parse($TEXT, options) {
}
next();
return params;
}
function parameter(used_parameters, symbol_type) {
@@ -1500,12 +1505,7 @@ function parse($TEXT, options) {
}
} else if (is("name")) {
used_parameters.add_parameter(S.token);
elements.push(new symbol_type({
start: S.token,
name: S.token.value,
end: S.token
}));
next();
elements.push(as_symbol(symbol_type));
} else {
croak("Invalid function parameter");
}
@@ -1522,7 +1522,7 @@ function parse($TEXT, options) {
}
if (is_expand) {
if (!is("punc", "]")) {
unexpected(); // Must be last element
croak("Rest element must be last element");
}
elements[elements.length - 1] = new AST_Expansion({
start: expand_token,
@@ -1547,19 +1547,30 @@ function parse($TEXT, options) {
} else {
expect(",");
}
if (is("expand", "...")) {
is_expand = true;
expand_token = S.token;
used_parameters.mark_spread(S.token);
next();
}
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
used_parameters.add_parameter(S.token);
elements.push(new AST_ObjectKeyVal({
start: prev(),
key: S.token.value,
value: new symbol_type({
start: S.token,
name: S.token.value,
end: S.token
}),
end: prev()
}));
next();
var start = prev();
var value = as_symbol(symbol_type);
if (is_expand) {
elements.push(new AST_Expansion({
start: expand_token,
expression: value,
end: value.end,
}));
} else {
elements.push(new AST_ObjectKeyVal({
start: start,
key: value.name,
value: value,
end: value.end,
}));
}
} else if (is("punc", "}")) {
continue; // Allow trailing hole
} else {
@@ -1589,7 +1600,12 @@ function parse($TEXT, options) {
}));
}
}
if (is("operator", "=")) {
if (is_expand) {
if (!is("punc", "}")) {
croak("Rest element must be last element");
}
}
else if (is("operator", "=")) {
used_parameters.mark_default_assignment(S.token);
next();
elements[elements.length - 1].value = new AST_DefaultAssign({
@@ -1611,12 +1627,7 @@ function parse($TEXT, options) {
});
} else if (is("name")) {
used_parameters.add_parameter(S.token);
next();
return new symbol_type({
start: prev(),
name: prev().value,
end: prev()
});
return as_symbol(symbol_type);
} else {
croak("Invalid function parameter");
}
@@ -1670,6 +1681,7 @@ function parse($TEXT, options) {
S.in_generator = S.in_function;
if (is_async)
S.in_async = S.in_function;
if (args) parameters(args);
if (block)
S.in_directives = true;
S.in_loop = 0;
@@ -1677,10 +1689,8 @@ function parse($TEXT, options) {
if (block) {
S.input.push_directives_stack();
var a = block_();
if (S.input.has_directive("use strict")) {
if (name) strict_verify_symbol(name);
if (args) args.forEach(strict_verify_symbol);
}
if (name) _verify_symbol(name);
if (args) args.forEach(_verify_symbol);
S.input.pop_directives_stack();
} else {
var a = expression(false);
@@ -1855,7 +1865,8 @@ function parse($TEXT, options) {
: !no_in && kind === "const" && S.input.has_directive("use strict")
? croak("Missing initializer in const declaration") : null,
end : prev()
})
});
if (def.name.name == "import") croak("Unexpected token: import");
}
a.push(def);
if (!is("punc", ","))
@@ -1907,12 +1918,14 @@ function parse($TEXT, options) {
} else {
args = [];
}
return subscripts(new AST_New({
var call = new AST_New({
start : start,
expression : newexp,
args : args,
end : prev()
}), allow_calls);
});
mark_pure(call);
return subscripts(call, allow_calls);
};
function as_atom_node() {
@@ -1974,9 +1987,6 @@ function parse($TEXT, options) {
names: ex.properties.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_ObjectKeyVal) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key]);
}
ex.value = to_fun_args(ex.value, 0, [ex.key]);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Hole) {
@@ -2030,8 +2040,29 @@ function parse($TEXT, options) {
}) : exprs.length == 1 ? exprs[0] : new AST_Sequence({
expressions: exprs
});
if (ex.start) {
var len = start.comments_before.length;
[].unshift.apply(ex.start.comments_before, start.comments_before);
start.comments_before = ex.start.comments_before;
start.comments_before_length = len;
if (len == 0 && start.comments_before.length > 0) {
var comment = start.comments_before[0];
if (!comment.nlb) {
comment.nlb = start.nlb;
start.nlb = false;
}
}
start.comments_after = ex.start.comments_after;
}
ex.start = start;
ex.end = S.token;
var end = prev();
if (ex.end) {
end.comments_before = ex.end.comments_before;
[].push.apply(ex.end.comments_after, end.comments_after);
end.comments_after = ex.end.comments_after;
}
ex.end = end;
if (ex instanceof AST_Call) mark_pure(ex);
return subscripts(ex, allow_calls);
case "[":
return subscripts(array_(), allow_calls);
@@ -2084,7 +2115,8 @@ function parse($TEXT, options) {
}));
while (S.token.end === false) {
next();
segments.push(expression());
handle_regexp();
segments.push(expression(true));
if (!is_token("template_substitution")) {
unexpected();
@@ -2143,7 +2175,18 @@ function parse($TEXT, options) {
if (!options.strict && is("punc", "}"))
// allow trailing comma
break;
start = S.token;
if (start.type == "expand") {
next();
a.push(new AST_Expansion({
start: start,
expression: expression(false),
end: prev(),
}));
continue;
}
var name = as_property_name();
var value;
@@ -2493,9 +2536,9 @@ function parse($TEXT, options) {
&& is_token(peek(), "punc")) {
exported_value = expression(false);
semicolon();
} else if ((node = statement()) instanceof AST_Definitions && is_default) {
} else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) {
unexpected(node.start);
} else if (node instanceof AST_Definitions || node instanceof AST_Defun || node instanceof AST_DefClass) {
} else if (node instanceof AST_Definitions || node instanceof AST_Lambda || node instanceof AST_DefClass) {
exported_definition = node;
} else if (node instanceof AST_SimpleStatement) {
exported_value = node.body;
@@ -2531,9 +2574,14 @@ function parse($TEXT, options) {
unexpected(tmp);
}
case "name":
if (tmp.value == "yield" && !is_token(peek(), "punc", ":")
&& S.input.has_directive("use strict") && !is_in_generator()) {
token_error(tmp, "Unexpected yield identifier inside strict mode");
if (tmp.value == "yield") {
if (is_in_generator()) {
token_error(tmp, "Yield cannot be used as identifier inside generators");
} else if (!is_token(peek(), "punc", ":")
&& !is_token(peek(), "punc", "(")
&& S.input.has_directive("use strict")) {
token_error(tmp, "Unexpected yield identifier inside strict mode");
}
}
case "string":
case "num":
@@ -2564,9 +2612,19 @@ function parse($TEXT, options) {
});
};
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
croak("Unexpected " + sym.name + " in strict mode", sym.start.line, sym.start.col, sym.start.pos);
function _verify_symbol(sym) {
var name = sym.name;
if (is_in_generator() && name == "yield") {
token_error(sym.start, "Yield cannot be used as identifier inside generators");
}
if (S.input.has_directive("use strict")) {
if (name == "yield") {
token_error(sym.start, "Unexpected yield identifier inside strict mode");
}
if (sym instanceof AST_SymbolDeclaration && (name == "arguments" || name == "eval")) {
token_error(sym.start, "Unexpected " + name + " in strict mode");
}
}
}
function as_symbol(type, noerror) {
@@ -2574,17 +2632,25 @@ function parse($TEXT, options) {
if (!noerror) croak("Name expected");
return null;
}
if (is("name", "yield") && S.input.has_directive("use strict")) {
token_error(S.prev, "Unexpected yield identifier inside strict mode");
}
var sym = _make_symbol(type);
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
strict_verify_symbol(sym);
}
_verify_symbol(sym);
next();
return sym;
};
function mark_pure(call) {
var start = call.start;
var comments = start.comments_before;
var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
while (--i >= 0) {
var comment = comments[i];
if (/[@#]__PURE__/.test(comment.value)) {
call.pure = comment;
break;
}
}
}
var subscripts = function(expr, allow_calls) {
var start = expr.start;
if (is("punc", ".")) {
@@ -2609,12 +2675,14 @@ function parse($TEXT, options) {
}
if (allow_calls && is("punc", "(")) {
next();
return subscripts(new AST_Call({
var call = new AST_Call({
start : start,
expression : expr,
args : call_args(),
end : prev()
}), true);
});
mark_pure(call);
return subscripts(call, true);
}
if (is("template_head")) {
return subscripts(new AST_PrefixedTemplateString({
@@ -2666,7 +2734,7 @@ function parse($TEXT, options) {
return ex;
}
var val = expr_atom(allow_calls, allow_arrows);
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) {
if (val instanceof AST_Arrow) unexpected();
val = make_unary(AST_UnaryPostfix, S.token, val);
val.start = start;
@@ -2696,7 +2764,8 @@ function parse($TEXT, options) {
var op = is("operator") ? S.token.value : null;
if (op == "in" && no_in) op = null;
if (op == "**" && left instanceof AST_UnaryPrefix
&& left.end === S.prev /* unary token in front not allowed, but allowed if prev is for example `)` */
/* unary token in front not allowed - parenthesis required */
&& !is_token(left.start, "punc", "(")
&& left.operator !== "--" && left.operator !== "++")
unexpected(left.start);
var prec = op != null ? PRECEDENCE[op] : null;
@@ -2792,7 +2861,7 @@ function parse($TEXT, options) {
next();
return _yield_expression();
} else if (S.input.has_directive("use strict")) {
token_error(S.token, "Unexpected yield identifier inside strict mode")
token_error(S.token, "Unexpected yield identifier inside strict mode");
}
}

View File

@@ -85,6 +85,36 @@ function find_builtins(reserved) {
}
}
function reserve_quoted_keys(ast, reserved) {
function add(name) {
push_uniq(reserved, name);
}
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key);
} else if (node instanceof AST_ObjectProperty && node.quote) {
add(node.key.name);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
}));
}
function addStrings(node, add) {
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) {
addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) {
add(node.value);
} else if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
}
return true;
}));
}
function mangle_properties(ast, options) {
options = defaults(options, {
builtins: false,
@@ -94,22 +124,24 @@ function mangle_properties(ast, options) {
only_cache: false,
regex: null,
reserved: null,
});
}, true);
var reserved = options.reserved;
if (!Array.isArray(reserved)) reserved = [];
if (!options.builtins) find_builtins(reserved);
var cache = options.cache;
if (cache == null) {
cache = {
cname: -1,
props: new Dictionary()
};
var cname = -1;
var cache;
if (options.cache) {
cache = options.cache.props;
cache.each(function(mangled_name) {
push_uniq(reserved, mangled_name);
});
} else {
cache = new Dictionary();
}
var regex = options.regex;
var keep_quoted = options.keep_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
@@ -122,12 +154,11 @@ function mangle_properties(ast, options) {
var names_to_mangle = [];
var unmangleable = [];
var to_keep = {};
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) {
add(node.key, keep_quoted && node.quote);
add(node.key);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above
@@ -137,18 +168,14 @@ function mangle_properties(ast, options) {
add(node.property);
}
else if (node instanceof AST_Sub) {
addStrings(node.property, keep_quoted);
}
else if (node instanceof AST_ConciseMethod) {
add(node.name.name);
addStrings(node.property, add);
}
}));
// step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) {
if (!(keep_quoted && node.quote))
node.key = mangle(node.key);
node.key = mangle(node.key);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter
@@ -157,27 +184,9 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
}
else if (node instanceof AST_Sub) {
if (!keep_quoted)
node.property = mangleStrings(node.property);
else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property);
}
else if (node instanceof AST_ConciseMethod) {
if (should_mangle(node.name.name)) {
node.name.name = mangle(node.name.name);
}
}
// else if (node instanceof AST_String) {
// if (should_mangle(node.value)) {
// AST_Node.warn(
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
// file : node.start.file,
// line : node.start.line,
// col : node.start.col,
// prop : node.value
// }
// );
// }
// }
}));
// only function declarations after this line
@@ -186,26 +195,20 @@ function mangle_properties(ast, options) {
if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) {
return cache.props.has(name);
return cache.has(name);
}
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true;
}
function should_mangle(name) {
if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name)
return cache.has(name)
|| names_to_mangle.indexOf(name) >= 0;
}
function add(name, keep) {
if (keep) {
to_keep[name] = true;
return;
}
function add(name) {
if (can_mangle(name))
push_uniq(names_to_mangle, name);
@@ -219,58 +222,29 @@ function mangle_properties(ast, options) {
return name;
}
var mangled = cache.props.get(name);
var mangled = cache.get(name);
if (!mangled) {
if (debug) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
if (can_mangle(debug_mangled)) {
mangled = debug_mangled;
}
}
// either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) {
// Note: `can_mangle()` does not check if the name collides with the `to_keep` set
// (filled with quoted properties when `keep_quoted` is set). Make sure we add this
// check so we don't collide with a quoted name.
do {
mangled = base54(++cache.cname);
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
mangled = base54(++cname);
} while (!can_mangle(mangled));
}
cache.props.set(name, mangled);
cache.set(name, mangled);
}
return mangled;
}
function addStrings(node, keep) {
var out = {};
try {
(function walk(node){
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Sequence) {
walk(node.expressions[node.expressions.length - 1]);
return true;
}
if (node instanceof AST_String) {
add(node.value, keep);
return true;
}
if (node instanceof AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Sequence) {

View File

@@ -43,16 +43,18 @@
"use strict";
function SymbolDef(scope, index, orig) {
function SymbolDef(scope, orig, init) {
this.name = orig.name;
this.orig = [ orig ];
this.init = init;
this.eliminated = 0;
this.scope = scope;
this.references = [];
this.replaced = 0;
this.global = false;
this.export = false;
this.mangled_name = null;
this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++;
};
@@ -116,7 +118,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var tw = new TreeWalker(function(node, descend){
if (node.is_block_scope()) {
var save_scope = scope;
scope = new AST_Scope(node);
node.block_scope = scope = new AST_Scope(node);
scope.init_scope_vars(save_scope);
if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with;
@@ -174,7 +176,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.references = [];
}
if (node instanceof AST_SymbolLambda) {
defun.def_function(node);
defun.def_function(node, node.name == "arguments" ? undefined : defun);
}
else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is
@@ -182,14 +184,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit
// later.
var parent_lambda = defun.parent_scope;
while (parent_lambda.is_block_scope()) {
parent_lambda = parent_lambda.parent_scope;
}
mark_export((node.scope = parent_lambda).def_function(node), 1);
mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node, defun), 1);
}
else if (node instanceof AST_SymbolClass) {
mark_export(defun.def_variable(node), 1);
mark_export(defun.def_variable(node, defun), 1);
}
else if (node instanceof AST_SymbolImport) {
scope.def_variable(node);
@@ -197,12 +195,32 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
else if (node instanceof AST_SymbolDefClass) {
// This deals with the name of the class being available
// inside the class.
mark_export((node.scope = defun.parent_scope).def_function(node), 1);
mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1);
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolLet
|| node instanceof AST_SymbolConst) {
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node);
var def;
if (node instanceof AST_SymbolBlockDeclaration) {
def = scope.def_variable(node);
} else {
def = defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
}
if (!all(def.orig, function(sym) {
if (sym === node) return true;
if (node instanceof AST_SymbolBlockDeclaration) {
return sym instanceof AST_SymbolLambda;
}
return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst);
})) {
js_error(
node.name + " redeclared",
node.start.file,
node.start.line,
node.start.col,
node.start.pos
);
}
if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2);
def.destructuring = in_destructuring;
if (defun !== scope) {
@@ -272,6 +290,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}
node.thedef = sym;
node.reference(options);
if (node.scope.is_block_scope()
&& !(sym.orig[0] instanceof AST_SymbolBlockDeclaration)) {
node.scope = node.scope.get_defun_scope();
}
return true;
}
// ensure mangling works if catch reuses a scope variable
@@ -300,6 +322,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
ref.reference(options);
});
node.thedef = def;
node.reference(options);
return true;
}
}));
@@ -317,10 +340,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
});
}
}
if (options.cache) {
this.cname = options.cache.cname;
}
});
AST_Toplevel.DEFMETHOD("def_global", function(node){
@@ -328,7 +347,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
if (globals.has(name)) {
return globals.get(name);
} else {
var g = new SymbolDef(this, globals.size(), node);
var g = new SymbolDef(this, node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
@@ -357,7 +376,7 @@ AST_IterationStatement.DEFMETHOD("is_block_scope", return_true);
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
this.def_variable(new AST_SymbolConst({
this.def_variable(new AST_SymbolFunarg({
name: "arguments",
start: this.start,
end: this.end
@@ -390,34 +409,37 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
AST_Scope.DEFMETHOD("def_function", function(symbol){
var def = this.def_variable(symbol);
AST_Scope.DEFMETHOD("def_function", function(symbol, init){
var def = this.def_variable(symbol, init);
if (!def.init) def.init = init;
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol);
AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
def.init = init;
}
} else {
def = new SymbolDef(this, symbol, init);
this.variables.set(symbol.name, def);
def.global = !this.parent_scope;
} else {
def = this.variables.get(symbol.name);
def.orig.push(symbol);
}
return symbol.thedef = def;
});
AST_Scope.DEFMETHOD("next_mangled", function(options){
var ext = this.enclosed;
function next_mangled(scope, options) {
var ext = scope.enclosed;
out: while (true) {
var m = base54(++this.cname);
var m = base54(++scope.cname);
if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling.
if (options.reserved.indexOf(m) >= 0) continue;
if (member(m, options.reserved)) continue;
// we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in
@@ -429,6 +451,18 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
}
return m;
}
}
AST_Scope.DEFMETHOD("next_mangled", function(options){
return next_mangled(this, options);
});
AST_Toplevel.DEFMETHOD("next_mangled", function(options){
var name;
do {
name = next_mangled(this, options);
} while (member(name, this.mangled_names));
return name;
});
AST_Function.DEFMETHOD("next_mangled", function(options, def){
@@ -442,7 +476,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
while (true) {
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
var name = next_mangled(this, options);
if (!tricky_name || tricky_name != name)
return name;
}
@@ -461,14 +495,6 @@ AST_Symbol.DEFMETHOD("unreferenced", function(){
&& !(this.scope.uses_eval || this.scope.uses_with);
});
AST_Symbol.DEFMETHOD("undeclared", function(){
return this.definition().undeclared;
});
AST_LabelRef.DEFMETHOD("undeclared", return_false);
AST_Label.DEFMETHOD("undeclared", return_false);
AST_Symbol.DEFMETHOD("definition", function(){
return this.thedef;
});
@@ -477,7 +503,7 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global;
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
options = defaults(options, {
eval : false,
ie8 : false,
@@ -487,15 +513,14 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
toplevel : false,
});
if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
push_uniq(options.reserved, "arguments");
return options;
});
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options);
// Never mangle arguments
options.reserved.push('arguments');
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of
@@ -503,12 +528,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var lname = -1;
var to_mangle = [];
var mangled_names = this.mangled_names = [];
if (options.cache) {
this.globals.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
});
this.globals.each(collect);
if (options.cache.props) {
options.cache.props.each(function(mangled_name) {
push_uniq(mangled_names, mangled_name);
});
}
}
var tw = new TreeWalker(function(node, descend){
@@ -520,13 +547,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Scope) {
var p = tw.parent(), a = [];
node.variables.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
a.push(symbol);
}
});
to_mangle.push.apply(to_mangle, a);
node.variables.each(collect);
return;
}
if (node instanceof AST_Label) {
@@ -538,7 +559,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var mangle_with_block_scope =
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
if (mangle_with_block_scope && options.reserved.indexOf(node.name) < 0) {
to_mangle.push(node.definition());
return;
}
@@ -548,11 +569,80 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
def.mangle(options);
});
if (options.cache) {
options.cache.cname = this.cname;
function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
}
});
AST_Toplevel.DEFMETHOD("find_unique_prefix", function(options) {
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
var cache = options.cache && options.cache.props;
var prefixes = Object.create(null);
options.reserved.forEach(add_prefix);
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());
}));
var prefix, i = 0;
do {
prefix = create_name(i++);
} while (prefixes[prefix]);
return prefix;
function add_prefix(name) {
if (/[0-9]$/.test(name)) {
prefixes[name.replace(/[0-9]+$/, "")] = true;
}
}
function add_def(def) {
var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
add_prefix(name);
}
function create_name(num) {
var name = "";
do {
name += letters[num % letters.length];
num = Math.floor(num / letters.length);
} while (num);
return name;
}
});
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
options = this._default_mangler_options(options);
var prefix = this.find_unique_prefix(options);
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
}));
function rename(def) {
if (def.global || def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return;
var d = def.redefined();
def.name = d ? d.name : prefix + def.id;
def.orig.forEach(function(sym) {
sym.name = def.name;
});
def.references.forEach(function(sym) {
sym.name = def.name;
});
}
});
AST_Node.DEFMETHOD("tail_node", return_this);
AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
options = this._default_mangler_options(options);
try {
@@ -581,7 +671,7 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
skip_string(node.consequent);
skip_string(node.alternative);
} else if (node instanceof AST_Sequence) {
skip_string(node.expressions[node.expressions.length - 1]);
skip_string(node.tail_node());
}
}
});

View File

@@ -60,17 +60,14 @@ TreeTransformer.prototype = new TreeWalker;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (x === undefined) {
if (!tw.after) {
x = this;
descend(x, tw);
} else {
tw.stack[tw.stack.length - 1] = x = this;
descend(x, tw);
x = this;
descend(x, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (y !== undefined) x = y;
}
}
tw.pop(this);
tw.pop();
return x;
});
};
@@ -262,11 +259,7 @@ TreeTransformer.prototype = new TreeWalker;
});
_(AST_TemplateString, function(self, tw) {
for (var i = 0; i < self.segments.length; i++) {
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
self.segments[i] = self.segments[i].transform(tw);
}
}
self.segments = do_list(self.segments, tw);
});
_(AST_PrefixedTemplateString, function(self, tw) {

View File

@@ -43,10 +43,6 @@
"use strict";
function slice(a, start) {
return Array.prototype.slice.call(a, start || 0);
};
function characters(str) {
return str.split("");
};
@@ -214,18 +210,6 @@ function mergeSort(array, cmp) {
return _ms(array);
};
function set_difference(a, b) {
return a.filter(function(el){
return b.indexOf(el) < 0;
});
};
function set_intersection(a, b) {
return a.filter(function(el){
return b.indexOf(el) >= 0;
});
};
// this function is taken from Acorn [1], written by Marijn Haverbeke
// [1] https://github.com/marijnh/acorn
function makePredicate(words) {
@@ -340,7 +324,7 @@ function first_in_statement(stack) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p.TYPE == "Call" && p.expression === node ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||

View File

@@ -1,20 +1,17 @@
{
"name": "uglify-es",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit for ES6+",
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.0.23",
"version": "3.3.5",
"engines": {
"node": ">=0.8.0"
},
"maintainers": [
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
],
"repository": {
"type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git"
},
"repository": "git+https://github.com/mishoo/UglifyJS2.git#harmony",
"bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues"
},
@@ -29,25 +26,29 @@
"LICENSE"
],
"dependencies": {
"commander": "~2.9.0",
"source-map": "~0.5.1"
"commander": "~2.12.1",
"source-map": "~0.6.1"
},
"devDependencies": {
"acorn": "~5.0.3",
"mocha": "~2.3.4",
"semver": "~5.3.0"
"acorn": "~5.2.1",
"mocha": "~3.5.1",
"semver": "~5.4.1"
},
"scripts": {
"test": "node test/run-tests.js"
},
"keywords": [
"uglify",
"uglify-js",
"uglify-es",
"uglify-js",
"minify",
"minifier",
"javascript",
"ecmascript",
"es5",
"es6",
"es7",
"es8",
"es2015",
"es2016",
"es2017",

View File

@@ -6,6 +6,7 @@
var createHash = require("crypto").createHash;
var fetch = require("./fetch");
var fork = require("child_process").fork;
var zlib = require("zlib");
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc");
@@ -20,6 +21,7 @@ var urls = [
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
"https://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.js",
];
var results = {};
var remaining = 2 * urls.length;
@@ -33,6 +35,7 @@ function done() {
console.log(info.log);
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("GZipped: ", info.gzip, "bytes");
console.log("SHA1 sum:", info.sha1);
if (info.code) {
failures.push(url);
@@ -51,6 +54,7 @@ urls.forEach(function(url) {
results[url] = {
input: 0,
output: 0,
gzip: 0,
log: ""
};
fetch(url, function(err, res) {
@@ -61,6 +65,10 @@ urls.forEach(function(url) {
}).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length;
}).pipe(zlib.createGzip({
level: zlib.Z_BEST_COMPRESSION
})).on("data", function(data) {
results[url].gzip += data.length;
}).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex");
done();

View File

@@ -203,50 +203,114 @@ constant_join_3: {
for_loop: {
options = {
unsafe : true,
unused : true,
evaluate : true,
reduce_vars : true
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
unused: true,
};
input: {
function f0() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}
var b = 0;
for (var i = 0; i < a.length; i++)
b += a[i];
return b;
}
function f1() {
var a = [1, 2, 3];
for (var i = 0, len = a.length; i < len; i++) {
console.log(a[i]);
}
var b = 0;
for (var i = 0, len = a.length; i < len; i++)
b += a[i];
return b;
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) {
a[i]++;
}
}
}
expect: {
function f0() {
var a = [1, 2, 3];
for (var i = 0; i < 3; i++)
console.log(a[i]);
}
function f1() {
var a = [1, 2, 3];
for (var i = 0; i < 3; i++)
console.log(a[i]);
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++)
a[i]++;
return a[2];
}
console.log(f0(), f1(), f2());
}
expect: {
function f0() {
var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++)
b += a[i];
return b;
}
function f1() {
var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++)
b += a[i];
return b;
}
function f2() {
var a = [1, 2, 3];
for (var i = 0; i < a.length; i++)
a[i]++;
return a[2];
}
console.log(f0(), f1(), f2());
}
expect_stdout: "6 6 4"
}
index: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a[1]);
}
expect: {
console.log(1, 2);
}
expect_stdout: "1 2"
}
length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a.length);
}
expect: {
console.log(2);
}
expect_stdout: "2"
}
index_length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a.length);
}
expect: {
console.log(1, 2);
}
expect_stdout: "1 2"
}

View File

@@ -213,7 +213,7 @@ no_leading_parentheses: {
async_identifiers: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
}
input: {
@@ -237,7 +237,7 @@ async_identifiers: {
async_function_expression: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
evaluate: true,
side_effects: true,
@@ -262,7 +262,7 @@ async_function_expression: {
issue_27: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
ecma: 6,
unused: true,
@@ -283,13 +283,15 @@ issue_27: {
issue_2105_1: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
ecma: 6,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
unused: true,
}
input: {
@@ -313,17 +315,12 @@ issue_2105_1: {
});
}
expect: {
(() => {
var quux = () => {
({
prop() {
console.log;
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=4"
@@ -334,6 +331,7 @@ issue_2105_2: {
collapse_vars: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -359,17 +357,12 @@ issue_2105_2: {
});
}
expect: {
(() => {
var quux = () => {
({
prop: () => {
console.log;
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -410,6 +403,7 @@ issue_2136_3: {
evaluate: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -437,6 +431,7 @@ call_args: {
ecma: 6,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -461,6 +456,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -487,6 +483,7 @@ issue_485_crashing_1530: {
ecma: 6,
evaluate: true,
inline: true,
side_effects: true,
}
input: {
(function(a) {
@@ -494,20 +491,19 @@ issue_485_crashing_1530: {
var b = 42;
})(this);
}
expect: {
this, void 0;
}
expect: {}
}
issue_2084: {
options = {
arrows: true,
unsafe_arrows: true,
collapse_vars: true,
conditionals: true,
ecma: 6,
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -540,3 +536,121 @@ issue_2084: {
expect_stdout: "0"
node_version: ">=4"
}
export_default_object_expression: {
options = {
arrows: true,
evaluate: true,
}
input: {
export default {
foo: 1 + 2,
bar() { return 4; },
get baz() { return this.foo; },
};
}
expect_exact: "export default{foo:3,bar:()=>4,get baz(){return this.foo}};"
}
concise_methods_with_computed_property2: {
options = {
arrows: true,
evaluate: true,
}
input: {
var foo = {
[[1]](v) {
return v;
}
};
console.log(foo[[1]]("PASS"));
}
expect_exact: 'var foo={[[1]]:v=>v};console.log(foo[[1]]("PASS"));'
expect_stdout: "PASS"
node_version: ">=4"
}
async_object_literal: {
options = {
arrows: true,
unsafe_arrows: true,
ecma: 6,
evaluate: true,
}
input: {
var obj = {
async a() {
return await foo(1 + 0);
},
anon: async function() {
return await foo(2 + 0);
}
};
}
expect: {
var obj = {
a: async () => await foo(1),
anon: async () => await foo(2)
};
}
}
issue_2271: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
unsafe_arrows: false,
}
input: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect_stdout: "PASS"
}
concise_method_with_super: {
options = {
arrows: true,
}
input: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

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

View File

@@ -16,7 +16,6 @@ asm_mixed: {
hoist_vars : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
negate_iife : true
};
@@ -104,3 +103,65 @@ asm_mixed: {
}
}
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}

View File

@@ -141,6 +141,7 @@ async_inline: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -292,3 +293,31 @@ async_arrow_iife_negate_iife: {
}
expect_exact: "(async()=>{await fetch()})();(()=>{plain()})();"
}
issue_2344_1: {
beautify = {
safari10: false,
}
input: {
async () => {
+await x;
await y;
return await z;
};
}
expect_exact: "async()=>{+await x;await y;return await z};"
}
issue_2344_2: {
beautify = {
safari10: true,
}
input: {
async () => {
+await x;
await y;
return await z;
};
}
expect_exact: "async()=>{+(await x);await y;return await z};"
}

File diff suppressed because it is too large Load Diff

View File

@@ -73,4 +73,42 @@ dont_change_in_or_instanceof_expressions: {
1 instanceof 1;
null instanceof null;
}
}
}
self_comparison_1: {
options = {
comparisons: true,
}
input: {
a === a;
a !== b;
b.c === a.c;
b.c !== b.c;
}
expect: {
a == a;
a !== b;
b.c === a.c;
b.c != b.c;
}
}
self_comparison_2: {
options = {
comparisons: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {}
var o = {};
console.log(f != f, o === o);
}
expect: {
function f() {}
var o = {};
console.log(false, true);
}
expect_stdout: "false true"
}

View File

@@ -21,7 +21,7 @@ concat_1: {
var c = 1 + x() + 2 + "boo";
var d = 1 + x() + 2 + 3 + "boo";
var e = 1 + x() + 2 + "X3boo";
var f = "\x00360\08\0";
var f = "\x00360\x008\0";
}
}

View File

@@ -166,22 +166,24 @@ cond_1: {
conditionals: true
};
input: {
var do_something; // if undeclared it's assumed to have side-effects
if (some_condition()) {
do_something(x);
} else {
do_something(y);
}
if (some_condition()) {
side_effects(x);
} else {
side_effects(y);
function foo(do_something, some_condition) {
if (some_condition) {
do_something(x);
} else {
do_something(y);
}
if (some_condition) {
side_effects(x);
} else {
side_effects(y);
}
}
}
expect: {
var do_something;
do_something(some_condition() ? x : y);
some_condition() ? side_effects(x) : side_effects(y);
function foo(do_something, some_condition) {
do_something(some_condition ? x : y);
some_condition ? side_effects(x) : side_effects(y);
}
}
}
@@ -190,16 +192,18 @@ cond_2: {
conditionals: true
};
input: {
var x, FooBar;
if (some_condition()) {
x = new FooBar(1);
} else {
x = new FooBar(2);
function foo(x, FooBar, some_condition) {
if (some_condition) {
x = new FooBar(1);
} else {
x = new FooBar(2);
}
}
}
expect: {
var x, FooBar;
x = new FooBar(some_condition() ? 1 : 2);
function foo(x, FooBar, some_condition) {
x = new FooBar(some_condition ? 1 : 2);
}
}
}
@@ -605,11 +609,47 @@ cond_8c: {
}
}
cond_9: {
options = {
conditionals: true,
}
input: {
function f(x, y) {
g() ? x(1) : x(2);
x ? (y || x)() : (y || x)();
x ? y(a, b) : y(d, b, c);
x ? y(a, b, c) : y(a, b, c);
x ? y(a, b, c) : y(a, b, f);
x ? y(a, b, c) : y(a, e, c);
x ? y(a, b, c) : y(a, e, f);
x ? y(a, b, c) : y(d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
expect: {
function f(x, y) {
g() ? x(1) : x(2);
x, (y || x)();
x ? y(a, b) : y(d, b, c);
x, y(a, b, c);
y(a, b, x ? c : f);
y(a, x ? b : e, c);
x ? y(a, b, c) : y(a, e, f);
y(x ? a : d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
}
ternary_boolean_consequent: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, side_effects:true
}
input: {
function f1() { return a == b ? true : x; }
@@ -637,7 +677,7 @@ ternary_boolean_alternative: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, side_effects:true
}
input: {
function f1() { return a == b ? x : true; }
@@ -1015,3 +1055,172 @@ delete_conditional_2: {
}
expect_stdout: true
}
issue_2535_1: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
passes: 2,
side_effects: true,
}
input: {
if (true || x()) y();
if (true && x()) y();
if (x() || true) y();
if (x() && true) y();
if (false || x()) y();
if (false && x()) y();
if (x() || false) y();
if (x() && false) y();
}
expect: {
y();
x() && y();
(x(), 1) && y();
x() && y();
x() && y();
x() && y();
(x(), 0) && y();
}
}
issue_2535_2: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
side_effects: true,
}
input: {
function x() {}
function y() {
return "foo";
}
console.log((x() || true) || y());
console.log((y() || true) || x());
console.log((x() || true) && y());
console.log((y() || true) && x());
console.log((x() && true) || y());
console.log((y() && true) || x());
console.log((x() && true) && y());
console.log((y() && true) && x());
console.log((x() || false) || y());
console.log((y() || false) || x());
console.log((x() || false) && y());
console.log((y() || false) && x());
console.log((x() && false) || y());
console.log((y() && false) || x());
console.log((x() && false) && y());
console.log((y() && false) && x());
}
expect: {
function x() {}
function y() {
return "foo";
}
console.log(x() || !0);
console.log(y() || !0);
console.log((x(), y()));
console.log((y(), x()));
console.log(!!x() || y());
console.log(!!y() || x());
console.log(x() && y());
console.log(y() && x());
console.log(x() || y());
console.log(y() || x());
console.log(!!x() && y());
console.log(!!y() && x());
console.log((x(), y()));
console.log((y(), x()));
console.log(x() && !1);
console.log(y() && !1);
}
expect_stdout: [
"true",
"foo",
"foo",
"undefined",
"foo",
"true",
"undefined",
"undefined",
"foo",
"foo",
"false",
"undefined",
"foo",
"undefined",
"undefined",
"false",
]
}
issue_2560: {
options = {
conditionals: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function log(x) {
console.log(x);
}
function foo() {
return log;
}
function bar() {
if (x !== (x = foo())) {
x(1);
} else {
x(2);
}
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect: {
function log(x) {
console.log(x);
}
function bar() {
x !== (x = log) ? x(1) : x(2);
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect_stdout: [
"1",
"2",
]
}
hoist_decl: {
options = {
conditionals: true,
join_vars: true,
sequences: true,
}
input: {
if (x()) {
var a;
y();
} else {
z();
var b;
}
}
expect: {
var a, b;
x() ? y() : z();
}
}

View File

@@ -12,6 +12,7 @@ issue_1191: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -44,6 +45,7 @@ issue_1194: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -72,6 +74,7 @@ issue_1396: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {
@@ -143,6 +146,7 @@ regexp_literal_not_const: {
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_funcs : true,
reduce_vars : true,
}
input: {

View File

@@ -129,8 +129,8 @@ dead_code_constant_boolean_should_warn_more: {
var bar;
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
var x = 10, y;
bar();
}
expect_stdout: true
@@ -165,8 +165,8 @@ dead_code_constant_boolean_should_warn_more_strict: {
var foo;
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
var x = 10, y;
bar();
}
expect_stdout: true
@@ -175,10 +175,11 @@ dead_code_constant_boolean_should_warn_more_strict: {
dead_code_block_decls_die: {
options = {
dead_code : true,
conditionals : true,
booleans : true,
evaluate : true
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
};
input: {
if (0) {
@@ -197,12 +198,14 @@ dead_code_block_decls_die: {
dead_code_const_declaration: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
reduce_vars : true,
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
loops: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
};
input: {
var unused;
@@ -224,13 +227,15 @@ dead_code_const_declaration: {
dead_code_const_annotation: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
loops: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
};
input: {
var unused;
@@ -276,13 +281,16 @@ dead_code_const_annotation_regex: {
dead_code_const_annotation_complex_scope: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
booleans: true,
conditionals: true,
dead_code: true,
evaluate: true,
loops: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
};
input: {
var unused_var;
@@ -325,6 +333,8 @@ try_catch_finally: {
conditionals: true,
dead_code: true,
evaluate: true,
passes: 2,
side_effects: true,
}
input: {
var a = 1;
@@ -377,3 +387,744 @@ accessor: {
}
expect: {}
}
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}
issue_2383_1: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
}
input: {
if (0) {
var {x, y} = foo();
}
}
expect: {
var x, y;
}
}
issue_2383_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
}
input: {
if (0) {
var {
x = 0,
y: [ w, , { z, p: q = 7 } ] = [ 1, 2, { z: 3 } ]
} = {};
}
console.log(x, q, w, z);
}
expect: {
var x, w, z, q;
console.log(x, q, w, z);
}
expect_stdout: "undefined undefined undefined undefined"
node_version: ">=6"
}
issue_2383_3: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
}
input: {
var b = 7, y = 8;
if (0) {
var a = 1, [ x, y, z ] = [ 2, 3, 4 ], b = 5;
}
console.log(a, x, y, z, b);
}
expect: {
var b = 7, y = 8;
var a, x, y, z, b;
console.log(a, x, y, z, b);
}
expect_stdout: "undefined undefined 8 undefined 7"
node_version: ">=6"
}
collapse_vars_assignment: {
options = {
collapse_vars: true,
dead_code: true,
passes: 2,
unused: true,
}
input: {
function f0(c) {
var a = 3 / c;
return a = a;
}
}
expect: {
function f0(c) {
return 3 / c;
}
}
}
collapse_vars_lvalues_drop_assign: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f0(x) { var i = ++x; return x += i; }
function f1(x) { var a = (x -= 3); return x += a; }
function f2(x) { var z = x, a = ++z; return z += a; }
}
expect: {
function f0(x) { var i = ++x; return x + i; }
function f1(x) { var a = (x -= 3); return x + a; }
function f2(x) { var z = x, a = ++z; return z + a; }
}
}
collapse_vars_misc1: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f10(x) { var a = 5, b = 3; return a += b; }
function f11(x) { var a = 5, b = 3; return a += --b; }
}
expect: {
function f10(x) { return 5 + 3; }
function f11(x) { var b = 3; return 5 + --b; }
}
}
return_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1(a, b, c) {
return a = x(), b = y(), b = a && (c >>= 5);
}
function f2() {
return e = x();
}
function f3(e) {
return e = x();
}
function f4() {
var e;
return e = x();
}
function f5(a) {
try {
return a = x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect: {
function f1(a, b, c) {
return a = x(), y(), a && (c >> 5);
}
function f2() {
return e = x();
}
function f3(e) {
return x();
}
function f4() {
return x();
}
function f5(a) {
try {
return x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect_stdout: [
"y",
"result 31",
"result 2",
"e: 2",
"result 3",
"result 4",
"result 5",
"6",
"result 6",
"caught -1",
"caught -2",
"caught -3",
"caught -4",
"50",
"result undefined",
"60",
"caught -6",
]
}
throw_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1() {
throw a = x();
}
function f2(a) {
throw a = x();
}
function f3() {
var a;
throw a = x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect: {
function f1() {
throw a = x();
}
function f2(a) {
throw x();
}
function f3() {
throw x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect_stdout: [
"caught 1",
"a: 1",
"caught 2",
"caught 3",
"4",
"a: 4",
"5",
"6",
"7",
"caught 7",
"a: 7",
"8",
"caught 8",
"9",
"caught 9",
"caught -1",
"caught -2",
"caught -3",
"null",
"50",
"undefined",
"null",
"caught -7",
"80",
"caught -8",
"undefined",
"caught -9",
]
}
issue_2597: {
options = {
dead_code: true,
}
input: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect_stdout: "PASS"
}
issue_2666: {
options = {
dead_code: true,
}
input: {
function f(a) {
return a = {
p: function() {
return a;
}
};
}
console.log(typeof f().p());
}
expect: {
function f(a) {
return a = {
p: function() {
return a;
}
};
}
console.log(typeof f().p());
}
expect_stdout: "object"
}
issue_2692: {
options = {
dead_code: true,
reduce_vars: false,
}
input: {
function f(a) {
return a = g;
function g() {
return a;
}
}
console.log(typeof f()());
}
expect: {
function f(a) {
return a = g;
function g() {
return a;
}
}
console.log(typeof f()());
}
expect_stdout: "function"
}
issue_2701: {
options = {
dead_code: true,
inline: false,
}
input: {
function f(a) {
return a = function() {
return function() {
return a;
};
}();
}
console.log(typeof f()());
}
expect: {
function f(a) {
return a = function() {
return function() {
return a;
};
}();
}
console.log(typeof f()());
}
expect_stdout: "function"
}

View File

@@ -65,10 +65,10 @@ nested_destructuring_objects: {
}
input: {
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
let [{d},e] = f;
var [{g},h] = i;
}
expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;';
expect_exact: 'const[{a},b]=c;let[{d},e]=f;var[{g},h]=i;';
}
destructuring_constdef_in_loops: {
@@ -262,6 +262,7 @@ destructuring_dont_evaluate_with_undefined_as_default_assignment: {
reduce_vars: {
options = {
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -274,8 +275,8 @@ reduce_vars: {
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
let [{d},e] = f;
var [{g},h] = i;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);
@@ -292,8 +293,8 @@ reduce_vars: {
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
let [{d},e] = f;
var [{g},h] = i;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
and: {
options = {
evaluate: true
evaluate: true,
side_effects: true,
}
input: {
var a;
@@ -76,7 +77,8 @@ and: {
or: {
options = {
evaluate: true
evaluate: true,
side_effects: true,
}
input: {
var a;
@@ -158,7 +160,8 @@ or: {
unary_prefix: {
options = {
evaluate: true
evaluate: true,
side_effects: true,
}
input: {
a = !0 && b;
@@ -344,22 +347,27 @@ unsafe_constant: {
unsafe_object: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o = { a: 1 };
console.log(
({a:1}) + 1,
({a:1}).a + 1,
({a:1}).b + 1,
({a:1}).a.b + 1
o + 1,
o.a + 1,
o.b + 1,
o.a.b + 1
);
}
expect: {
var o = { a: 1 };
console.log(
({a:1}) + 1,
o + 1,
2,
({a:1}).b + 1,
o.b + 1,
1..b + 1
);
}
@@ -368,22 +376,27 @@ unsafe_object: {
unsafe_object_nested: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o = { a: { b: 1 } };
console.log(
({a:{b:1}}) + 1,
({a:{b:1}}).a + 1,
({a:{b:1}}).b + 1,
({a:{b:1}}).a.b + 1
o + 1,
o.a + 1,
o.b + 1,
o.a.b + 1
);
}
expect: {
var o = { a: { b: 1 } };
console.log(
({a:{b:1}}) + 1,
({a:{b:1}}).a + 1,
({a:{b:1}}).b + 1,
o + 1,
o.a + 1,
o.b + 1,
2
);
}
@@ -392,21 +405,26 @@ unsafe_object_nested: {
unsafe_object_complex: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o = { a: { b: 1 }, b: 1 };
console.log(
({a:{b:1},b:1}) + 1,
({a:{b:1},b:1}).a + 1,
({a:{b:1},b:1}).b + 1,
({a:{b:1},b:1}).a.b + 1
o + 1,
o.a + 1,
o.b + 1,
o.a.b + 1
);
}
expect: {
var o = { a: { b: 1 }, b: 1 };
console.log(
({a:{b:1},b:1}) + 1,
({a:{b:1},b:1}).a + 1,
o + 1,
o.a + 1,
2,
2
);
@@ -416,22 +434,27 @@ unsafe_object_complex: {
unsafe_object_repeated: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o = { a: { b: 1 }, a: 1 };
console.log(
({a:{b:1},a:1}) + 1,
({a:{b:1},a:1}).a + 1,
({a:{b:1},a:1}).b + 1,
({a:{b:1},a:1}).a.b + 1
o + 1,
o.a + 1,
o.b + 1,
o.a.b + 1
);
}
expect: {
var o = { a: { b: 1 }, a: 1 };
console.log(
({a:{b:1},a:1}) + 1,
o + 1,
2,
({a:{b:1},a:1}).b + 1,
o.b + 1,
1..b + 1
);
}
@@ -441,6 +464,7 @@ unsafe_object_repeated: {
unsafe_object_accessor: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
}
@@ -464,10 +488,11 @@ unsafe_object_accessor: {
}
}
unsafe_function: {
prop_function: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
properties: true,
side_effects: true,
}
input: {
console.log(
@@ -480,9 +505,9 @@ unsafe_function: {
expect: {
console.log(
({a:{b:1},b:function(){}}) + 1,
({a:{b:1},b:function(){}}).a + 1,
({a:{b:1},b:function(){}}).b + 1,
({a:{b:1},b:function(){}}).a.b + 1
({b:1}) + 1,
function(){} + 1,
2
);
}
expect_stdout: true
@@ -708,10 +733,11 @@ unsafe_string_bad_index: {
expect_stdout: true
}
unsafe_prototype_function: {
prototype_function: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
properties: true,
side_effects: true,
}
input: {
var a = ({valueOf: 0}) < 1;
@@ -730,8 +756,8 @@ unsafe_prototype_function: {
var d = ({toString: 0}) + "";
var e = (({valueOf: 0}) + "")[2];
var f = (({toString: 0}) + "")[2];
var g = ({valueOf: 0}).valueOf();
var h = "" + ({toString: 0});
var g = 0();
var h = 0();
}
}
@@ -739,6 +765,7 @@ call_args: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -761,6 +788,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -1091,6 +1119,7 @@ Infinity_NaN_undefined_LHS: {
issue_1964_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: false,
unused: true,
@@ -1098,6 +1127,7 @@ issue_1964_1: {
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
@@ -1105,16 +1135,21 @@ issue_1964_1: {
expect: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect_stdout: "b"
expect_stdout: [
"\\s",
"b",
]
}
issue_1964_2: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: true,
unused: true,
@@ -1122,17 +1157,22 @@ issue_1964_2: {
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
console.log(/\s/.source);
return "a b c".split(/\s/)[1];
}
console.log(f());
}
expect_stdout: "b"
expect_stdout: [
"\\s",
"b",
]
}
array_slice_index: {
@@ -1162,3 +1202,234 @@ string_charCodeAt: {
}
expect_stdout: "NaN"
}
issue_2207_1: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(String.fromCharCode(65));
console.log(Math.max(3, 6, 2, 7, 3, 4));
console.log(Math.cos(1.2345));
console.log(Math.cos(1.2345) - Math.sin(4.321));
console.log(Math.pow(Math.PI, Math.E - Math.LN10));
}
expect: {
console.log("A");
console.log(7);
console.log(Math.cos(1.2345));
console.log(1.2543732512566947);
console.log(1.6093984514472044);
}
expect_stdout: true
}
issue_2207_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Math.E);
console.log(Math.LN10);
console.log(Math.LN2);
console.log(Math.LOG2E);
console.log(Math.LOG10E);
console.log(Math.PI);
console.log(Math.SQRT1_2);
console.log(Math.SQRT2);
}
expect: {
console.log(Math.E);
console.log(Math.LN10);
console.log(Math.LN2);
console.log(Math.LOG2E);
console.log(Math.LOG10E);
console.log(Math.PI);
console.log(Math.SQRT1_2);
console.log(Math.SQRT2);
}
expect_stdout: true
}
issue_2207_3: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Number.MAX_VALUE);
console.log(Number.MIN_VALUE);
console.log(Number.NaN);
console.log(Number.NEGATIVE_INFINITY);
console.log(Number.POSITIVE_INFINITY);
}
expect: {
console.log(Number.MAX_VALUE);
console.log(5e-324);
console.log(NaN);
console.log(-1/0);
console.log(1/0);
}
expect_stdout: true
}
issue_2231_1: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.keys(void 0));
}
expect: {
console.log(Object.keys(void 0));
}
expect_stdout: true
}
issue_2231_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.getOwnPropertyNames(null));
}
expect: {
console.log(Object.getOwnPropertyNames(null));
}
expect_stdout: true
}
self_comparison_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}
self_comparison_2: {
options = {
evaluate: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}
issue_2535_1: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
if ((x() || true) || y()) z();
if ((x() || true) && y()) z();
if ((x() && true) || y()) z();
if ((x() && true) && y()) z();
if ((x() || false) || y()) z();
if ((x() || false) && y()) z();
if ((x() && false) || y()) z();
if ((x() && false) && y()) z();
}
expect: {
if (x(), 1) z();
if (x(), y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x(), y()) z();
if (x(), 0) z();
}
}
issue_2535_2: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
(x() || true) || y();
(x() || true) && y();
(x() && true) || y();
(x() && true) && y();
(x() || false) || y();
(x() || false) && y();
(x() && false) || y();
(x() && false) && y();
}
expect: {
x(),
x(), y(),
x() || y(),
x() && y(),
x() || y(),
x() && y(),
x(), y(),
x();
}
}
issue_2535_3: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(Object(1) && 1 && 2);
console.log(Object(1) && true && 1 && 2 && Object(2));
console.log(Object(1) && true && 1 && null && 2 && Object(2));
console.log(2 == Object(1) || 0 || void 0 || null);
console.log(2 == Object(1) || 0 || void 0 || null || Object(2));
console.log(2 == Object(1) || 0 || void 0 || "ok" || null || Object(2));
}
expect: {
console.log(Object(1) && 2);
console.log(Object(1) && Object(2));
console.log(Object(1) && null);
console.log(2 == Object(1) || null);
console.log(2 == Object(1) || Object(2));
console.log(2 == Object(1) || "ok");
}
expect_stdout: true
expect_warnings: [
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1409,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1410,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1411,20]",
"WARN: Condition left of && always false [test/compress/evaluate.js:1411,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1412,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1413,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1414,20]",
"WARN: Condition left of || always true [test/compress/evaluate.js:1414,20]",
]
}

View File

@@ -26,3 +26,46 @@ expand_parameters: {
expect_exact: "(function(a,...b){});(function(...args){});"
}
avoid_spread_in_ternary: {
options = {
comparisons: true,
conditionals: true,
evaluate: true,
}
input: {
function print(...x) {
console.log(...x);
}
var a = [1, 2], b = [3, 4], m = Math;
if (m)
print(a);
else
print(b);
if (m)
print(...a);
else
print(b);
if (m.no_such_property)
print(a);
else
print(...b);
}
expect: {
function print(...x) {
console.log(...x);
}
var a = [ 1, 2 ], b = [ 3, 4 ], m = Math;
print(m ? a : b);
m ? print(...a) : print(b);
m.no_such_property ? print(a) : print(...b);
}
expect_stdout: [
"[ 1, 2 ]",
"1 2",
"3 4",
]
node_version: ">=6"
}

View File

@@ -124,6 +124,7 @@ async_func: {
issue_2134_1: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -141,6 +142,7 @@ issue_2134_1: {
issue_2134_2: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -226,3 +228,219 @@ keyword_valid_3: {
export { default as default } from "module.js";
}
}
dynamic_import: {
mangle = {
toplevel: true,
}
input: {
import traditional from './traditional.js';
function imp(x) {
return import(x);
}
import("module_for_side_effects.js");
let dynamic = import("some/module.js");
dynamic.foo();
}
expect: {
import o from "./traditional.js";
function t(o) {
return import(o);
}
import("module_for_side_effects.js");
let r = import("some/module.js");
r.foo();
}
}
trailing_comma: {
beautify = {
beautify: true,
}
input: {
export const a = 1;
}
expect_exact: "export const a = 1;"
}
export_default_anonymous_function: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default function () {
foo();
}
}
expect_exact: "export default function(){foo()};"
}
export_default_arrow: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default () => foo();
}
expect_exact: "export default()=>foo();"
}
export_default_anonymous_generator: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default function * () {
yield foo();
}
}
expect_exact: "export default function*(){yield foo()};"
}
export_default_anonymous_async_function: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default async function() {
return await foo();
}
}
expect_exact: "export default async function(){return await foo()};"
}
export_default_async_arrow_function: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default async () => await foo();
}
expect_exact: "export default async()=>await foo();"
}
export_default_named_generator: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default function * gen() {
yield foo();
}
}
expect_exact: "export default function*gen(){yield foo()};"
}
export_default_named_async_function: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default async function bar() {
return await foo();
}
}
expect_exact: "export default async function bar(){return await foo()};"
}
export_default_anonymous_class: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default class {
constructor() {
foo();
}
};
}
expect_exact: "export default class{constructor(){foo()}};"
}
export_default_anonymous_function_not_call: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default function(){}(foo);
}
// FIXME: should be `export default function(){};foo;`
expect_exact: "export default function(){}(foo);"
}
export_default_anonymous_generator_not_call: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default function*(){}(foo);
}
// agrees with `acorn` and `babylon 7`
expect_exact: "export default function*(){};foo;"
}
export_default_anonymous_async_function_not_call: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export default async function(){}(foo);
}
// agrees with `acorn` and `babylon 7`
expect_exact: "export default async function(){};foo;"
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,6 +37,7 @@ object: {
VALUE: 42,
},
},
side_effects: true,
unsafe: true,
}
input: {
@@ -140,9 +141,9 @@ mixed: {
console.log(CONFIG);
}
expect_warnings: [
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]',
]
}
@@ -183,6 +184,7 @@ issue_2167: {
global_defs: {
"@isDevMode": "function(){}",
},
passes: 2,
side_effects: true,
}
input: {

View File

@@ -13,7 +13,8 @@ arrow_function_parens_2: {
typeof_arrow_functions: {
options = {
evaluate: true
evaluate: true,
typeofs: true,
}
input: {
var foo = typeof (x => null);
@@ -211,13 +212,13 @@ export_statement: {
}
input: {
export default 1 + 2;
export var foo = 4;
export let foo = 6;
export const foo = 6;
export function foo() {};
export class foo { };
export var a = 4;
export let b = 6;
export const c = 6;
export function d() {};
export class e {};
}
expect_exact: "export default 3;export var foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};"
expect_exact: "export default 3;export var a=4;export let b=6;export const c=6;export function d(){};export class e{};"
}
export_default_object_expression: {
@@ -695,3 +696,519 @@ export_default_class_decl: {
}
expect_exact: "export default class Car{};export class Cab{};"
}
object_rest_spread: {
mangle = {
toplevel: true,
}
input: {
var { w: w1, ...V } = { w: 7, x: 1, y: 2 }; console.log(w1, V);
let { w: w2, ...L } = { w: 8, x: 3, y: 4 }; console.log(w2, L);
const { w: w3, ...C } = { w: 9, x: 5, y: 6 }; console.log(w3, C);
let b;
({ b, ...V } = { a: 1, b: 2, c: 3 }); console.log(V);
({ b, ...L } = { a: 4, b: 5, c: 6 }); console.log(L);
(function({ y, ...p }){ console.log(p); })({ x: 1, y: 2, z: 3 });
(({ y, ...p }) => { console.log(p); })({ x: 4, y: 5, z: 6 });
const T = { a: 1, b: 2 }; console.log({ ...T, w: 0, ...{}, ...L, ...{K: 9} });
}
expect: {
var { w: o, ...l } = { w: 7, x: 1, y: 2 }; console.log(o, l);
let { w: c, ...n } = { w: 8, x: 3, y: 4 }; console.log(c, n);
const { w: e, ...s } = { w: 9, x: 5, y: 6 }; console.log(e, s);
let g;
({ b: g, ...l } = { a: 1, b: 2, c: 3 }); console.log(l);
({ b: g, ...n } = { a: 4, b: 5, c: 6 }); console.log(n);
(function({ y: o, ...l }) { console.log(l); })({ x: 1, y: 2, z: 3 });
(({ y: o, ...l }) => { console.log(l); })({ x: 4, y: 5, z: 6 });
const w = { a: 1, b: 2 }; console.log({ ...w, w: 0, ...{}, ...n, ...{ K: 9 } });
}
}
object_spread_unsafe: {
options = {
collapse_vars: true,
evaluate: true,
join_vars: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
var o1 = { x: 1, y: 2 };
var o2 = { x: 3, z: 4 };
var cloned = { ...o1 };
var merged = { ...o1, ...o2 };
console.log(cloned, merged);
}
expect: {
var o = { x: 1, y: 2 }, l = { ...o }, x = { ...o, ...{ x: 3, z: 4 } };
console.log(l, x);
}
}
array_spread_of_sequence: {
mangle = {
toplevel: true,
}
input: {
var a = [1];
console.log([...(a, a)]);
console.log([...a, a]);
console.log([...(a || a)]);
console.log([...a || a]);
}
expect: {
var o = [1];
console.log([...(o, o)]);
console.log([...o, o]);
console.log([...o || o]);
console.log([...o || o]);
}
expect_stdout: [
"[ 1 ]",
"[ 1, [ 1 ] ]",
"[ 1 ]",
"[ 1 ]",
]
node_version: ">=6"
}
object_spread_of_sequence: {
mangle = {
toplevel: true,
}
input: {
var a = {x: 1};
console.log({ ...(a, a) });
console.log({ ...a, a });
console.log({ ...(a || a) });
console.log({ ...a || a });
}
expect: {
var o = { x: 1 };
console.log({ ...(o, o) });
console.log({ ...o, a: o });
console.log({ ...o || o });
console.log({ ...o || o });
}
}
// issue 2316
class_name_can_be_preserved_with_reserved: {
mangle = {
reserved: [ "Foo" ],
}
input: {
function x() {
class Foo {}
Foo.bar;
class Bar {}
Bar.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var Bar = class Bar {};
Bar.bar;
}
}
expect: {
function x() {
class Foo {}
Foo.bar;
class a {}
a.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var a = class a {};
a.bar;
}
}
}
issue_2345: {
options = {
evaluate: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
console.log([...[3, 2, 1]].join("-"));
var a = [3, 2, 1];
console.log([...a].join("-"));
}
expect: {
console.log([...[3, 2, 1]].join("-"));
var a = [3, 2, 1];
console.log([...a].join("-"));
}
expect_stdout: [
"3-2-1",
"3-2-1",
]
node_version: ">=6"
}
issue_2349: {
mangle = {}
input: {
function foo(boo, key) {
const value = boo.get();
return value.map(({[key]: bar}) => bar);
}
console.log(foo({
get: () => [ {
blah: 42
} ]
}, "blah"));
}
expect: {
function foo(o, n) {
const t = o.get();
return t.map(({[n]: o}) => o);
}
console.log(foo({
get: () => [ {
blah: 42
} ]
}, "blah"));
}
expect_stdout: [
"[ 42 ]",
]
node_version: ">=7"
}
issue_2349b: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
evaluate: true,
inline: true,
passes: 3,
properties: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
side_effects: true,
unsafe_arrows: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
function foo(boo, key) {
const value = boo.get();
return value.map(function({[key]: bar}){ return bar; });
}
console.log(foo({
get: function() {
return [ {
blah: 42
} ];
}
}, "blah"));
}
expect: {
console.log([ {
blah: 42
} ].map(({["blah"]: l}) => l));
}
expect_stdout: [
"[ 42 ]",
]
node_version: ">=7"
}
shorthand_keywords: {
beautify = {
ecma: 6,
}
input: {
var foo = 0,
async = 1,
await = 2,
implements = 3,
package = 4,
private = 5,
protected = 6,
static = 7,
yield = 8;
console.log({
foo: foo,
0: 0,
NaN: NaN,
async: async,
await: await,
false: false,
implements: implements,
null: null,
package: package,
private: private,
protected: protected,
static: static,
this: this,
true: true,
undefined: undefined,
yield: yield,
});
}
expect_exact: "var foo=0,async=1,await=2,implements=3,package=4,private=5,protected=6,static=7,yield=8;console.log({foo,0:0,NaN:NaN,async,await,false:false,implements:implements,null:null,package:package,private:private,protected:protected,static:static,this:this,true:true,undefined:void 0,yield});"
expect_stdout: true
node_version: ">=4"
}
array_literal_with_spread_1: {
options = {
properties: true,
side_effects: true,
}
input: {
var f = (x) => [...x][0];
console.log(f(["PASS"]));
}
expect: {
var f = x => [ ...x ][0];
console.log(f([ "PASS" ]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
array_literal_with_spread_2: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log([10, ...[], 20, ...[30, 40], 50]["length"]);
console.log([10, ...[], 20, ...[30, 40], 50][0]);
console.log([10, ...[], 20, ...[30, 40], 50][1]);
console.log([10, ...[], 20, ...[30, 40], 50][2]);
console.log([10, ...[], 20, ...[30, 40], 50][3]);
console.log([10, ...[], 20, ...[30, 40], 50][4]);
console.log([10, ...[], 20, ...[30, 40], 50][5]);
}
expect: {
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ]["length"]);
console.log(10);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][1]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][2]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][3]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][4]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][5]);
}
expect_stdout: [
"5",
"10",
"20",
"30",
"40",
"50",
"undefined",
]
node_version: ">=6"
}
array_literal_with_spread_3: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log([10, 20][0]);
console.log([10, 20][1]);
console.log([10, 20][2]);
console.log([...[], 10, 20][0]);
console.log([...[], 10, 20][1]);
console.log([...[], 10, 20][2]);
console.log([10, ...[], 20][0]);
console.log([10, ...[], 20][1]);
console.log([10, ...[], 20][2]);
console.log([10, 20, ...[]][0]);
console.log([10, 20, ...[]][1]);
console.log([10, 20, ...[]][2]);
}
expect: {
console.log(10);
console.log(20);
console.log([ 10, 20 ][2]);
console.log([...[], 10, 20][0]);
console.log([...[], 10, 20][1]);
console.log([...[], 10, 20][2]);
console.log(10);
console.log([10, ...[], 20][1]);
console.log([10, ...[], 20][2]);
console.log(10);
console.log(20);
console.log([10, 20, ...[]][2]);
}
expect_stdout: [
"10",
"20",
"undefined",
"10",
"20",
"undefined",
"10",
"20",
"undefined",
"10",
"20",
"undefined",
]
node_version: ">=6"
}
array_literal_with_spread_4: {
options = {
properties: true,
side_effects: true,
}
input: {
function t(x) {
console.log("(" + x + ")");
return 10 * x;
}
console.log([t(1), t(2)][0]);
console.log([t(1), t(2)][1]);
console.log([t(1), t(2)][2]);
console.log([...[], t(1), t(2)][0]);
console.log([...[], t(1), t(2)][1]);
console.log([...[], t(1), t(2)][2]);
console.log([t(1), ...[], t(2)][0]);
console.log([t(1), ...[], t(2)][1]);
console.log([t(1), ...[], t(2)][2]);
console.log([t(1), t(2), ...[]][0]);
console.log([t(1), t(2), ...[]][1]);
console.log([t(1), t(2), ...[]][2]);
}
expect: {
function t(x) {
console.log("(" + x + ")");
return 10 * x;
}
console.log([ t(1), t(2) ][0]);
console.log((t(1), t(2)));
console.log([ t(1), t(2) ][2]);
console.log([ ...[], t(1), t(2) ][0]);
console.log([ ...[], t(1), t(2) ][1]);
console.log([ ...[], t(1), t(2) ][2]);
console.log([ t(1), t(2) ][0]);
console.log([ t(1), ...[], t(2) ][1]);
console.log([ t(1), ...[], t(2) ][2]);
console.log([ t(1), t(2) ][0]);
console.log((t(1), t(2)));
console.log([ t(1), t(2), ...[] ][2]);
}
expect_stdout: [
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
]
node_version: ">=6"
}
object_literal_method_using_arguments: {
options = {
arrows: true,
}
input: {
console.log(({
m() {
return arguments[0];
}
}).m("PASS"));
}
expect: {
console.log(({
m() {
return arguments[0];
}
}).m("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
class_method_using_arguments: {
options = {
arrows: true,
}
input: {
console.log(new class {
m() {
return arguments[0];
}
}().m("PASS"));
}
expect: {
console.log(new class {
m() {
return arguments[0];
}
}().m("PASS"));
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2676: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
class A {}
A.a = 42;
}
expect: {
(class {}).a = 42;
}
}

View File

@@ -0,0 +1,899 @@
issue_2377_1: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
var obj_foo = 1, obj_cube = function(x) {
return x * x * x;
};
console.log(obj_foo, obj_cube(3));
}
expect_stdout: "1 27"
}
issue_2377_2: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, (x = 3, x * x * x));
var x;
}
expect_stdout: "1 27"
}
issue_2377_3: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
passes: 4,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, 27);
}
expect_stdout: "1 27"
}
direct_access_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect_stdout: "2 1"
}
direct_access_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
var f = function(k) {
if (o[k]) return "PASS";
};
console.log(f("a"));
}
expect: {
var o = { a: 1 };
console.log(function(k) {
if (o[k]) return "PASS";
}("a"));
}
expect_stdout: "PASS"
}
direct_access_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect_stdout: "1"
}
single_use: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
bar: function() {
return 42;
},
};
console.log(obj.bar());
}
expect: {
console.log({
bar: function() {
return 42;
},
}.bar());
}
}
name_collision_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj = {
foo: 3,
bar: 4,
"b-r": 5,
"b+r": 6,
"b!r": 7,
};
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
}
f();
}
expect: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj_foo$0 = 3,
obj_bar = 4,
obj_b_r = 5,
obj_b_r$0 = 6,
obj_b_r$1 = 7;
console.log(obj_foo, obj_foo$0, obj_bar, obj_b_r, obj_b_r$0, obj_b_r$1);
}
f();
}
expect_stdout: "1 3 4 5 6 7"
}
name_collision_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
0: function(x) {
return x;
},
1: function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5), o__$0, o__$1);
}
expect_stdout: "true 4 6 2 3"
}
name_collision_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
0: function(x) {
return x;
},
1: function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5));
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5));
}
expect_stdout: "true 4 6"
}
contains_this_1: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p);
}
expect: {
console.log(1, 1);
}
expect_stdout: "1 1"
}
contains_this_2: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u);
}
expect: {
console.log(1, 1, function() {
return this === this;
});
}
expect_stdout: true
}
contains_this_3: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect_stdout: "1 1 true"
}
hoist_class: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_classnames: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function run(c, v) {
return new c(v).value;
}
var o = {
p: class Foo {
constructor(value) {
this.value = value * 10;
}
},
x: 1,
y: 2,
};
console.log(o.p.name, o.p === o.p, run(o.p, o.x), run(o.p, o.y));
}
expect: {
function run(c, v) {
return new c(v).value;
}
var o_p = class Foo {
constructor(value) {
this.value = 10 * value;
}
};
console.log(o_p.name, true, run(o_p, 1), run(o_p, 2));
}
node_version: ">=6"
expect_stdout: "Foo true 10 20"
}
hoist_class_with_new: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_classnames: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
p: class Foo {
constructor(value) {
this.value = value * 10;
}
},
x: 1,
y: 2,
};
console.log(o.p.name, o.p === o.p, new o.p(o.x).value, new o.p(o.y).value);
}
expect: {
var o_p = class Foo {
constructor(value) {
this.value = 10 * value;
}
};
console.log(o_p.name, true, new o_p(1).value, new o_p(2).value);
}
node_version: ">=6"
expect_stdout: "Foo true 10 20"
}
hoist_function_with_call: {
options = {
comparisons: true,
evaluate: true,
hoist_props: true,
inline: true,
keep_fnames: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
p: function Foo(value) {
return 10 * value;
},
x: 1,
y: 2
};
console.log(o.p.name, o.p === o.p, o.p(o.x), o.p(o.y));
}
expect: {
var o = {
p: function Foo(value) {
return 10 * value;
},
x: 1,
y: 2
};
console.log(o.p.name, o.p == o.p, o.p(o.x), o.p(o.y));
}
expect_stdout: "Foo true 10 20"
}
new_this: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
f: function(a) {
this.b = a;
}
};
console.log(new o.f(o.a).b, o.b);
}
expect: {
console.log(new function(a) {
this.b = a;
}(1).b, 2);
}
expect_stdout: "1 2"
}
issue_2462: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
export const Foo = {
a: 1,
b: () => 2
};
}
expect: {
export const Foo = {
a: 1,
b: () => 2
};
}
}
issue_2473_1: {
options = {
hoist_props: false,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_2: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_3: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect_stdout: "1 2"
}
issue_2473_4: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
(function() {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
})();
}
expect: {
(function() {
var o_a = 1, o_b = 2;
console.log(o_a, o_b);
})();
}
expect_stdout: "1 2"
}
issue_2508_1: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ 1 ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})([ 1 ]);
}
expect_stdout: true
}
issue_2508_2: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: 2 },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})({ b: 2 });
}
expect_stdout: true
}
issue_2508_3: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_4: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_5: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: function(x) {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = function(x) {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2508_6: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: x => {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = x => {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2519: {
options = {
collapse_vars: true,
evaluate: true,
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
function testFunc() {
var dimensions = {
minX: 5,
maxX: 6,
};
var scale = 1;
var d = {
x: (dimensions.maxX + dimensions.minX) / 2,
};
return d.x * scale;
}
console.log(testFunc());
}
expect: {
function testFunc() {
return 1 * ((6 + 5) / 2);
}
console.log(testFunc());
}
expect_stdout: "5.5"
}
toplevel_const: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: false,
}
input: {
const a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect: {
const a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect_stdout: "3"
}
toplevel_let: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: false,
}
input: {
let a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect: {
let a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect_stdout: "3"
node_version: ">=6"
}
toplevel_var: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: false,
}
input: {
var a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect: {
var a = {
b: 1,
c: 2
};
console.log(a.b + a.c);
}
expect_stdout: "3"
}

View File

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

View File

@@ -384,3 +384,73 @@ issue_1317_strict: {
expect_stdout: "1"
node_version: ">=4"
}
if_var_return: {
options = {
conditionals: true,
if_return: true,
join_vars: true,
sequences: true,
}
input: {
function f() {
var a;
return;
var b;
}
function g() {
var a;
if (u()) {
var b;
return v();
var c;
}
var d;
if (w()) {
var e;
return x();
var f;
} else {
var g;
y();
var h;
}
var i;
z();
var j;
}
}
expect: {
function f() {
var a, b;
}
function g() {
var a, b, c, d, e, f, g, h, i, j;
return u() ? v() : w() ? x() : (y(), z(), void 0);
}
}
}
if_if_return_return: {
options = {
conditionals: true,
if_return: true,
}
input: {
function f(a, b) {
if (a) {
if (b)
return b;
return;
}
g();
}
}
expect: {
function f(a, b) {
if (a)
return b || void 0;
g();
}
}
}

View File

@@ -2,7 +2,7 @@ non_hoisted_function_after_return: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true
if_return: true, join_vars: true, side_effects: true
}
input: {
function foo(x) {
@@ -38,7 +38,7 @@ non_hoisted_function_after_return_2a: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
if_return: true, join_vars: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
@@ -71,11 +71,13 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
"WARN: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
"WARN: pass 1: last_count: 37, count: 18",
]
}
@@ -83,7 +85,7 @@ non_hoisted_function_after_return_2b: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
if_return: true, join_vars: true, side_effects: true,
collapse_vars: false
}
input: {
@@ -109,11 +111,11 @@ non_hoisted_function_after_return_2b: {
}
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:103,12]",
]
}
@@ -121,7 +123,7 @@ non_hoisted_function_after_return_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true
if_return: true, join_vars: true, side_effects: true
}
input: {
"use strict";
@@ -151,10 +153,10 @@ non_hoisted_function_after_return_strict: {
}
expect_stdout: "8 7"
expect_warnings: [
'WARN: Dropping unreachable code [test/compress/issue-1034.js:131,16]',
"WARN: Dropping unreachable code [test/compress/issue-1034.js:134,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:137,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:138,21]"
"WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:140,21]",
]
}
@@ -162,7 +164,7 @@ non_hoisted_function_after_return_2a_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
if_return: true, join_vars: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
@@ -194,17 +196,19 @@ non_hoisted_function_after_return_2a_strict: {
}
expect_stdout: "5 6"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:173,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:173,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:176,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:176,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:173,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:180,21]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:181,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:176,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:178,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]",
"WARN: pass 0: last_count: Infinity, count: 48",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:178,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:180,16]",
"WARN: pass 1: last_count: 48, count: 29",
]
}
@@ -212,7 +216,7 @@ non_hoisted_function_after_return_2b_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
if_return: true, join_vars: true, side_effects: true,
collapse_vars: false
}
input: {
@@ -243,10 +247,10 @@ non_hoisted_function_after_return_2b_strict: {
expect_stdout: "5 6"
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:231,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:235,12]",
]
}

View File

@@ -14,6 +14,7 @@ const_declaration: {
const_pragma: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};
@@ -29,6 +30,7 @@ const_pragma: {
not_const: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
};

View File

@@ -190,7 +190,6 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
sequences: false,
keep_infinity: false,
@@ -253,7 +252,6 @@ assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
sequences: false,
keep_infinity: true,

View File

@@ -14,7 +14,7 @@ issue_1212_debug_false: {
keep_fargs : true,
if_return : true,
join_vars : true,
cascade : true,
collapse_vars : true,
side_effects : true,
}
input: {
@@ -52,7 +52,7 @@ issue_1212_debug_true: {
keep_fargs : true,
if_return : true,
join_vars : true,
cascade : true,
collapse_vars : true,
side_effects : true,
}
input: {

View File

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

View File

@@ -9,7 +9,6 @@ string_plus_optimization: {
unused : true,
if_return : true,
join_vars : true,
cascade : true,
hoist_funs : true,
};
input: {

View File

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

View File

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

View File

@@ -32,7 +32,6 @@ conditional_false_stray_else_in_loop: {
hoist_vars : true,
join_vars : true,
if_return : true,
cascade : true,
conditionals : false,
}
input: {

View File

@@ -11,7 +11,6 @@ same_variable_in_multiple_for_loop: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -54,7 +53,6 @@ same_variable_in_multiple_forOf: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -96,7 +94,6 @@ same_variable_in_multiple_forIn: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -138,7 +135,6 @@ different_variable_in_multiple_for_loop: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -181,7 +177,6 @@ different_variable_in_multiple_forOf: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -223,7 +218,6 @@ different_variable_in_multiple_forIn: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
@@ -265,7 +259,6 @@ more_variable_in_multiple_for: {
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}

View File

@@ -2,6 +2,7 @@ chained_evaluation_1: {
options = {
collapse_vars: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -28,6 +29,7 @@ chained_evaluation_2: {
options = {
collapse_vars: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}

View File

@@ -2,7 +2,7 @@
issue_1639_1: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
join_vars: true,
@@ -26,7 +26,7 @@ issue_1639_1: {
}
expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, !1) var ignore = 0;
if (--b, 0) var ignore = 0;
console.log(a, b);
}
expect_stdout: true
@@ -35,7 +35,7 @@ issue_1639_1: {
issue_1639_2: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
join_vars: true,
@@ -57,7 +57,7 @@ issue_1639_2: {
expect: {
var a = 100, b = 10;
function f19() {
++a, 1;
++a, 0;
}
f19(),
console.log(a, b);
@@ -68,7 +68,7 @@ issue_1639_2: {
issue_1639_3: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
evaluate: true,
sequences: true,

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,7 @@
mangle_props: {
mangle_props = {}
mangle = {
properties: true,
}
input: {
var obj = {
undefined: 1,
@@ -54,10 +56,12 @@ mangle_props: {
}
numeric_literal: {
mangle = {
properties: true,
}
beautify = {
beautify: true,
}
mangle_props = {}
input: {
var obj = {
0: 0,

View File

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

View File

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

View File

@@ -177,6 +177,7 @@ export_mangle_2: {
export_mangle_3: {
options = {
collapse_vars: true,
unused: true,
}
mangle = {
toplevel: true,
@@ -195,6 +196,7 @@ export_mangle_3: {
export_mangle_4: {
options = {
collapse_vars: true,
unused: true,
}
mangle = {
toplevel: true,

View File

@@ -36,9 +36,10 @@ compress_new_function_with_destruct: {
compress_new_function_with_destruct_arrows: {
options = {
arrows: true,
unsafe_arrows: true,
unsafe: true,
unsafe_Func: true,
ecma: 6
ecma: 6,
}
beautify = {
ecma: 6

View File

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

View File

@@ -64,3 +64,27 @@ strings_concat: {
);
}
}
regexp: {
options = {
evaluate: true,
unsafe: true,
}
input: {
RegExp("foo");
RegExp("bar", "ig");
RegExp(foo);
RegExp("bar", ig);
RegExp("should", "fail");
}
expect: {
/foo/;
/bar/ig;
RegExp(foo);
RegExp("bar", ig);
RegExp("should", "fail");
}
expect_warnings: [
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:78,2]',
]
}

View File

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

View File

@@ -3,6 +3,7 @@ collapse_vars_constants: {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -240,6 +241,7 @@ negate_iife_issue_1073: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
unused: true,
@@ -267,6 +269,7 @@ issue_1288_side_effects: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -299,6 +302,7 @@ inner_var_for_in_1: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -330,6 +334,7 @@ issue_1595_3: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -448,7 +453,7 @@ pure_annotation_2: {
drop_fargs: {
options = {
cascade: true,
collapse_vars: true,
inline: true,
keep_fargs: false,
side_effects: true,
@@ -471,7 +476,7 @@ drop_fargs: {
keep_fargs: {
options = {
cascade: true,
collapse_vars: true,
inline: true,
keep_fargs: true,
side_effects: true,

View File

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

View File

@@ -17,6 +17,6 @@ wrongly_optimized: {
foo();
}
// TODO: optimize to `func(), bar()`
(func(), 0) || bar();
(func(), 1) && bar();
}
}

View File

@@ -100,7 +100,7 @@ wrongly_optimized: {
foo();
}
// TODO: optimize to `func(), bar()`
if (func(), !0) bar();
if (func(), 1) bar();
}
}

View File

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

View File

@@ -18,7 +18,6 @@ dont_mangle_arguments: {
hoist_vars : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
negate_iife : false
};

View File

@@ -1,7 +1,8 @@
this_binding_conditionals: {
options = {
conditionals: true,
evaluate : true
evaluate: true,
side_effects: true,
};
input: {
(1 && a)();
@@ -51,6 +52,7 @@ this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
};
input: {
var c = a; c();

View File

@@ -2,7 +2,7 @@ eval_collapse_vars: {
options = {
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, side_effects:true
};
input: {
function f1() {

View File

@@ -2,7 +2,7 @@ issue979_reported: {
options = {
sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, side_effects:true
}
input: {
function f1() {
@@ -32,7 +32,7 @@ issue979_test_negated_is_best: {
options = {
sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, side_effects:true
}
input: {
function f3() {

View File

@@ -192,9 +192,11 @@ keep_collapse_const_in_own_block_scope_2: {
evaluate: {
options = {
loops: true,
dead_code: true,
evaluate: true,
loops: true,
passes: 2,
side_effects: true,
};
input: {
while (true) {
@@ -480,3 +482,57 @@ do_switch: {
} while (false);
}
}
in_parenthesis_1: {
input: {
for (("foo" in {});0;);
}
expect_exact: 'for(("foo"in{});0;);'
}
in_parenthesis_2: {
input: {
for ((function(){ "foo" in {}; });0;);
}
expect_exact: 'for(function(){"foo"in{}};0;);'
}
init_side_effects: {
options = {
loops: true,
side_effects: true,
};
input: {
for (function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 10; i++) console.log(i);
}
expect: {
for (i = 0; i < 5; i++) console.log(i);
for (; i < 10; i++) console.log(i);
}
expect_stdout: true
}
dead_code_condition: {
options = {
dead_code: true,
evaluate: true,
loops: true,
sequences: true,
}
input: {
for (var a = 0, b = 5; (a += 1, 3) - 3 && b > 0; b--) {
var c = function() {
b--;
}(a++);
}
console.log(a);
}
expect: {
var c;
var a = 0, b = 5;
a += 1, 0,
console.log(a);
}
expect_stdout: "1"
}

View File

@@ -98,3 +98,19 @@ new_with_assignement_expression: {
new y([a, b] = [3, 4]);
}
}
dot_parenthesis_1: {
input: {
console.log(new (Math.random().constructor) instanceof Number);
}
expect_exact: "console.log(new(Math.random().constructor)instanceof Number);"
expect_stdout: "true"
}
dot_parenthesis_2: {
input: {
console.log(typeof new function(){Math.random()}.constructor);
}
expect_exact: "console.log(typeof new function(){Math.random()}.constructor);"
expect_stdout: "function"
}

View File

@@ -126,6 +126,67 @@ computed_property_names: {
expect_exact: 'obj({["x"+"x"]:6});'
}
convert_computed_props_to_regular_ones: {
options = {
booleans: true,
computed_props: true,
evaluate: true,
}
input: {
var o = {
["hi"]: 0,
["A" + 1]: 1,
[/B/]: 2,
[100 + 23]: 3,
[1 + .5]: 4,
[Math.PI]: 5,
[undefined]: 6,
[true]: 7,
[false]: 8,
[null]: 9,
[Infinity]: 10,
[NaN]: 11,
};
for (var k in o) {
console.log(k, o[k]);
}
}
expect: {
var o = {
hi: 0,
A1: 1,
[/B/]: 2,
123: 3,
1.5: 4,
[Math.PI]: 5,
// leave these problematic cases as is
[void 0]: 6,
[!0]: 7,
[!1]: 8,
[null]: 9,
[1 / 0]: 10,
[NaN]: 11
};
for (var k in o) console.log(k, o[k]);
}
expect_stdout: [
"123 3",
"hi 0",
"A1 1",
"/B/ 2",
"1.5 4",
"3.141592653589793 5",
"undefined 6",
"true 7",
"false 8",
"null 9",
"Infinity 10",
"NaN 11",
]
node_version: ">=6"
}
computed_property_names_evaluated_1: {
options = {
evaluate: true
@@ -284,9 +345,11 @@ concise_methods_with_various_property_names: {
}
concise_methods_and_mangle_props: {
mangle_props = {
regex: /_/
};
mangle = {
properties: {
regex: /_/,
},
}
input: {
function x() {
obj = {
@@ -510,3 +573,443 @@ variable_as_computed_property: {
}
expect_exact: "function getLine(header){return{[header]:{}}}"
}
prop_func_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
emit: function NamedFunctionExpression() {
console.log("PASS");
},
run: function() {
this.emit();
}
}).run();
}
expect: {
({
emit: function NamedFunctionExpression() {
console.log("PASS");
},
run() {
this.emit();
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=6"
}
prop_arrow_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
run: () => {
console.log("PASS");
}
}).run();
}
expect: {
({
run() {
console.log("PASS");
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=6"
}
concise_method_to_prop_arrow: {
options = {
arrows: true,
ecma: 6,
}
input: {
console.log(({ a: () => 1 }).a());
console.log(({ a: () => { return 2; } }).a());
console.log(({ a() { return 3; } }).a());
console.log(({ a() { return this.b; }, b: 4 }).a());
}
expect: {
console.log({ a: () => 1 }.a());
console.log({ a: () => 2 }.a());
console.log({ a: () => 3 }.a());
console.log({ a() { return this.b; }, b: 4 }.a());
}
expect_stdout: [
"1",
"2",
"3",
"4",
]
node_version: ">=4"
}
prop_func_to_async_concise_method: {
options = {
ecma: 8,
unsafe_methods: true,
}
input: {
({
run: async function() {
console.log("PASS");
}
}).run();
}
expect: {
({
async run() {
console.log("PASS");
}
}).run();
}
expect_stdout: "PASS"
node_version: ">=8"
}
prop_func_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
null: function(x, y){ x(y); },
123: function(x, y){ x(y); },
"A B": function(x, y){ x(y); },
p1: function(x, y){ x(y); },
p2: function*(x, y){ yield x(y); },
p3: async function(x, y){ await x(y); },
[c1]: function(x, y){ x(y); },
[c2]: function*(x, y){ yield x(y); },
[c3]: async function(x, y){ await x(y); },
});
}
expect: {
({
null(x, y) { x(y); },
123(x, y) { x(y); },
"A B"(x, y) { x(y); },
p1(x, y) { x(y); },
*p2(x, y) { yield x(y); },
async p3(x, y) { await x(y); },
[c1](x, y) { x(y); },
*[c2](x, y) { yield x(y); },
async [c3](x, y) { await x(y); },
});
}
}
prop_arrows_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
null: (x, y) => { x(y); },
123: (x, y) => { x(y); },
"A B": (x, y) => { x(y); },
p1: (x, y) => { x(y); },
p3: async (x, y) => { await x(y); },
[c1]: (x, y) => { x(y); },
[c3]: async (x, y) => { await x(y); },
});
}
expect: {
({
null(x, y) { x(y); },
123(x, y) { x(y); },
"A B"(x, y) { x(y); },
p1(x, y) { x(y); },
async p3(x, y) { await x(y); },
[c1](x, y) { x(y); },
async [c3](x, y) { await x(y); },
});
}
}
prop_arrow_with_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_no_this: function() { run(); },
func_with_this: function() { run(this); },
arrow_no_this: () => { run(); },
arrow_with_this: () => { run(this); },
};
for (var key in foo) foo[key]();
}
expect: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_no_this() { run(); },
func_with_this() { run(this); },
arrow_no_this() { run(); },
arrow_with_this: () => { run(this); },
};
for (var key in foo) foo[key]();
}
expect_stdout: [
"undefined",
"foo",
"undefined",
"global",
]
node_version: ">=4"
}
prop_arrow_with_nested_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_func_this: function() { (function() { run(this); })(); },
func_arrow_this: function() { (() => { run(this); })(); },
arrow_func_this: () => { (function() { run(this); })(); },
arrow_arrow_this: () => { (() => { run(this); })(); },
};
for (var key in foo) foo[key]();
}
expect: {
function run(arg) {
console.log(arg === this ? "global" : arg === foo ? "foo" : arg);
}
var foo = {
func_func_this() { (function() { run(this); })(); },
func_arrow_this() { (() => { run(this); })(); },
arrow_func_this() { (function() { run(this); })(); },
arrow_arrow_this: () => { (() => { run(this); })(); },
};
for (var key in foo) foo[key]();
}
expect_stdout: [
"global",
"foo",
"global",
"global",
]
node_version: ">=4"
}
issue_2554_1: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var obj = {
["x" + ""]: 1,
["method" + ""]() {
this.s = "PASS";
},
get ["g" + ""]() {
return this.x;
},
set ["s" + ""](value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect: {
var obj = {
x: 1,
method() {
this.s = "PASS";
},
get g() {
return this.x;
},
set s(value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_2: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var instance = new class {
constructor() {
this.x = 2;
}
["method" + ""]() {
this.s = "PASS";
}
get ["g" + ""]() {
return this.x;
}
set ["s" + ""](value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect: {
var instance = new class {
constructor() {
this.x = 2;
}
method() {
this.s = "PASS";
}
get g() {
return this.x;
}
set s(value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_3: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var foo = {
[1 + 0]: 1,
[2 + 0]() {
this[4] = "PASS";
},
get [3 + 0]() {
return this[1];
},
set [4 + 0](value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect: {
var foo = {
1: 1,
2() {
this[4] = "PASS";
},
get 3() {
return this[1];
},
set 4(value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_4: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var bar = new class {
constructor() {
this[1] = 2;
}
[2 + 0]() {
this[4] = "PASS";
}
get [3 + 0]() {
return this[1];
}
set [4 + 0](value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect: {
var bar = new class {
constructor() {
this[1] = 2;
}
2() {
this[4] = "PASS";
}
get 3() {
return this[1];
}
set 4(value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_5: {
options = {
computed_props: true,
evaluate: true,
}
input: {
new class {
["constructor"]() {
console.log("FAIL");
}
"constructor"() {
console.log("PASS");
}
}();
}
expect: {
new class {
["constructor"]() {
console.log("FAIL");
}
constructor() {
console.log("PASS");
}
}();
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -142,11 +142,11 @@ destructuring_arguments_3: {
}
input: {
function fn3({x: {y: {z: {} = 42}}}) {}
const { cover = (function () {}), xCover = (0, function() {}) } = {};
let { cover = (function () {}), xCover = (0, function() {}) } = {};
var { cover = (function () {}), xCover = (0, function() {}) } = {};
const { a = (function () {}), b = (0, function() {}) } = {};
let { c = (function () {}), d = (0, function() {}) } = {};
var { e = (function () {}), f = (0, function() {}) } = {};
}
expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{cover=function(){},xCover=(0,function(){})}={};let{cover=function(){},xCover=(0,function(){})}={};var{cover=function(){},xCover=(0,function(){})}={};"
expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{a=function(){},b=(0,function(){})}={};let{c=function(){},d=(0,function(){})}={};var{e=function(){},f=(0,function(){})}={};"
}
default_arguments: {

View File

@@ -1,7 +1,8 @@
keep_properties: {
options = {
properties: false
};
evaluate: true,
properties: false,
}
input: {
a["foo"] = "bar";
}
@@ -12,9 +13,12 @@ keep_properties: {
dot_properties: {
options = {
evaluate: true,
properties: true,
}
beautify = {
ie8: true,
};
}
input: {
a["foo"] = "bar";
a["if"] = "if";
@@ -35,9 +39,12 @@ dot_properties: {
dot_properties_es5: {
options = {
evaluate: true,
properties: true,
}
beautify = {
ie8: false,
};
}
input: {
a["foo"] = "bar";
a["if"] = "if";
@@ -57,8 +64,8 @@ dot_properties_es5: {
sub_properties: {
options = {
evaluate: true,
properties: true
};
properties: true,
}
input: {
a[0] = 0;
a["0"] = 1;
@@ -77,18 +84,18 @@ sub_properties: {
a[3.14] = 3;
a.if = 4;
a["foo bar"] = 5;
a[NaN] = 6;
a[null] = 7;
a.NaN = 6;
a.null = 7;
a[void 0] = 8;
}
}
evaluate_array_length: {
options = {
evaluate: true,
properties: true,
unsafe: true,
evaluate: true
};
}
input: {
a = [1, 2, 3].length;
a = [1, 2, 3].join()["len" + "gth"];
@@ -105,10 +112,10 @@ evaluate_array_length: {
evaluate_string_length: {
options = {
evaluate: true,
properties: true,
unsafe: true,
evaluate: true
};
}
input: {
a = "foo".length;
a = ("foo" + "bar")["len" + "gth"];
@@ -124,9 +131,11 @@ evaluate_string_length: {
}
mangle_properties: {
mangle_props = {
keep_quoted: false
};
mangle = {
properties: {
keep_quoted: false,
},
}
input: {
a["foo"] = "bar";
a.color = "red";
@@ -135,21 +144,24 @@ mangle_properties: {
a['run']({color: "blue", foo: "baz"});
}
expect: {
a["o"] = "bar";
a.a = "red";
x = {r: 10};
a.b(x.r, a.o);
a['b']({a: "blue", o: "baz"});
a["a"] = "bar";
a.b = "red";
x = {o: 10};
a.r(x.o, a.a);
a['r']({b: "blue", a: "baz"});
}
}
mangle_unquoted_properties: {
options = {
properties: false
evaluate: true,
properties: false,
}
mangle_props = {
builtins: true,
keep_quoted: true
mangle = {
properties: {
builtins: true,
keep_quoted: true,
},
}
beautify = {
beautify: false,
@@ -178,24 +190,26 @@ mangle_unquoted_properties: {
function f1() {
a["foo"] = "bar";
a.color = "red";
a.o = 2;
x = {"bar": 10, f: 7};
a.f = 9;
a.r = 2;
x = {"bar": 10, b: 7};
a.b = 9;
}
function f2() {
a.foo = "bar";
a['color'] = "red";
x = {bar: 10, f: 7};
a.f = 9;
a.o = 3;
x = {bar: 10, b: 7};
a.b = 9;
a.r = 3;
}
}
}
mangle_debug: {
mangle_props = {
debug: ""
};
mangle = {
properties: {
debug: "",
},
}
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -207,9 +221,11 @@ mangle_debug: {
}
mangle_debug_true: {
mangle_props = {
debug: true
};
mangle = {
properties: {
debug: true,
},
}
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -221,9 +237,11 @@ mangle_debug_true: {
}
mangle_debug_suffix: {
mangle_props = {
debug: "XYZ"
};
mangle = {
properties: {
debug: "XYZ",
},
}
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -236,13 +254,16 @@ mangle_debug_suffix: {
mangle_debug_suffix_keep_quoted: {
options = {
properties: false
evaluate: true,
properties: false,
}
mangle_props = {
builtins: true,
keep_quoted: true,
debug: "XYZ",
reserved: []
mangle = {
properties: {
builtins: true,
debug: "XYZ",
keep_quoted: true,
reserved: [],
},
}
beautify = {
beautify: false,
@@ -548,12 +569,18 @@ native_prototype: {
}
input: {
Array.prototype.splice.apply(a, [1, 2, b, c]);
Function.prototype.call.apply(console.log, console, [ "foo" ]);
Number.prototype.toFixed.call(Math.PI, 2);
Object.prototype.hasOwnProperty.call(d, "foo");
RegExp.prototype.test.call(/foo/, "bar");
String.prototype.indexOf.call(e, "bar");
}
expect: {
[].splice.apply(a, [1, 2, b, c]);
(function() {}).call.apply(console.log, console, [ "foo" ]);
0..toFixed.call(Math.PI, 2);
({}).hasOwnProperty.call(d, "foo");
/t/.test.call(/foo/, "bar");
"".indexOf.call(e, "bar");
}
}
@@ -659,3 +686,694 @@ accessor_this: {
expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);'
expect_stdout: "1 2 2"
}
issue_2208_1: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
p: function() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
}
issue_2208_2: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
a: 42,
p: function() {
return this.a;
}
}.p());
}
expect: {
console.log({
a: 42,
p: function() {
return this.a;
}
}.p());
}
expect_stdout: "42"
}
issue_2208_3: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
a = 42;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
}
issue_2208_4: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
function foo() {}
console.log({
a: foo(),
p: function() {
return 42;
}
}.p());
}
expect: {
function foo() {}
console.log((foo(), function() {
return 42;
})());
}
expect_stdout: "42"
}
issue_2208_5: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
p: "FAIL",
p: function() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
}
issue_2208_6: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
p: () => 42
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=4"
}
issue_2208_7: {
options = {
ecma: 6,
inline: true,
properties: true,
side_effects: true,
unsafe_arrows: true,
}
input: {
console.log({
p() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
node_version: ">=4"
}
issue_2208_8: {
options = {
ecma: 6,
inline: true,
properties: true,
side_effects: true,
unsafe_arrows: true,
}
input: {
console.log({
*p() {
return x();
}
}.p());
console.log({
async p() {
return await x();
}
}.p());
}
expect: {
console.log({
*p() {
return x();
}
}.p());
console.log((async () => {
return await x();
})());
}
}
issue_2208_9: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
a = 42;
console.log({
p: () => {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
node_version: ">=4"
}
methods_keep_quoted_true: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
class C { "Quoted"(){} Unquoted(){} }
f1({ "Quoted"(){}, Unquoted(){}, "Prop": 3 });
f2({ "Quoted": function(){} });
f3({ "Quoted": ()=>{} });
}
expect_exact: "class C{Quoted(){}o(){}}f1({Quoted(){},o(){},Prop:3});f2({Quoted(){}});f3({Quoted(){}});"
}
methods_keep_quoted_false: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
keep_quoted: false,
},
}
input: {
class C { "Quoted"(){} Unquoted(){} }
f1({ "Quoted"(){}, Unquoted(){}, "Prop": 3 });
f2({ "Quoted": function(){} });
f3({ "Quoted": ()=>{} });
}
expect_exact: "class C{o(){}d(){}}f1({o(){},d(){},e:3});f2({o(){}});f3({o(){}});"
}
methods_keep_quoted_from_dead_code: {
options = {
arrows: true,
booleans: true,
conditionals: true,
dead_code: true,
ecma: 6,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
class C { Quoted(){} Unquoted(){} }
f1({ Quoted(){}, Unquoted(){}, "Prop": 3 });
f2({ Quoted: function(){} });
f3({ Quoted: ()=>{} });
0 && obj["Quoted"];
}
expect_exact: "class C{Quoted(){}o(){}}f1({Quoted(){},o(){},Prop:3});f2({Quoted(){}});f3({Quoted(){}});"
}
issue_2256: {
options = {
side_effects: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
({ "keep": 1 });
g.keep = g.change;
}
expect: {
g.keep = g.g;
}
}
issue_2321: {
options = {
ecma: 6,
unsafe_methods: false,
}
input: {
var f = {
foo: function(){ console.log("foo") },
bar() { console.log("bar") }
};
var foo = new f.foo();
var bar = f.bar();
}
expect: {
var f = {
foo: function() {
console.log("foo");
},
bar() {
console.log("bar");
}
};
var foo = new f.foo();
var bar = f.bar();
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=6"
}
unsafe_methods_regex: {
options = {
ecma: 6,
unsafe_methods: /^[A-Z1]/,
}
input: {
var f = {
123: function(){ console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar") },
Baz: function(){ console.log("baz") },
BOO: function(){ console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect: {
var f = {
123() { console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar"); },
Baz() { console.log("baz") },
BOO() { console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect_stdout: [
"123",
"foo",
"bar",
"baz",
"boo",
"null",
"undefined",
]
node_version: ">=6"
}
lhs_prop_1: {
options = {
evaluate: true,
properties: true,
}
input: {
console.log(++{
a: 1
}.a);
}
expect: {
console.log(++{
a: 1
}.a);
}
expect_stdout: "2"
}
lhs_prop_2: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
[1][0] = 42;
(function(a) {
a.b = "g";
})("abc");
(function(a) {
a[2] = "g";
})("def");
(function(a) {
a[""] = "g";
})("ghi");
}
expect: {
[1][0] = 42;
"abc".b = "g";
"def"[2] = "g";
"ghi"[""] = "g";
}
}
literal_duplicate_key_side_effects: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log({
a: "FAIL",
a: console.log ? "PASS" : "FAIL"
}.a);
}
expect: {
console.log(console.log ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
prop_side_effects_1: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
bar: function() {
return C + C;
}
};
console.log(obj.bar());
}
expect: {
console.log(1);
var obj = {
bar: function() {
return 2;
}
};
console.log(obj.bar());
}
expect_stdout: [
"1",
"2",
]
}
prop_side_effects_2: {
options = {
evaluate: true,
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
"": function() {
return C + C;
}
};
console.log(obj[""]());
}
expect: {
console.log(1);
console.log(2);
}
expect_stdout: [
"1",
"2",
]
}
accessor_1: {
options = {
properties: true,
}
input: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect_stdout: "PASS"
node_version: ">=4"
}
accessor_2: {
options = {
properties: true,
}
input: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect_stdout: true
}
array_hole: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log(
[ 1, 2, , 3][1],
[ 1, 2, , 3][2],
[ 1, 2, , 3][3]
);
}
expect: {
console.log(2, void 0, 3);
}
expect_stdout: "2 undefined 3"
}
computed_property: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log({
a: "bar",
[console.log("foo")]: 42,
}.a);
}
expect: {
console.log([
"bar",
console.log("foo")
][0]);
}
expect_stdout: [
"foo",
"bar"
]
node_version: ">=4"
}
new_this: {
options = {
properties: true,
side_effects: true,
}
input: {
new {
f: function(a) {
this.a = a;
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
}
issue_2513: {
options = {
evaluate: true,
properties: true,
}
input: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"["Infinity"]);
console.log("c"[0/0], "d"["NaN"]);
console.log("e"[void 0], "f"["undefined"]);
}(0, 0, 0);
}
expect: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"[1/0]);
console.log("c".NaN, "d".NaN);
console.log("e"[void 0], "f"[void 0]);
}(0, 0, 0);
}
expect_stdout: [
"undefined undefined",
"undefined undefined",
"undefined undefined",
]
}
const_prop_assign_strict: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
function Simulator() {
/abc/.index = 1;
this._aircraft = [];
}
(function() {}).prototype.destroy = x();
}
expect: {
function Simulator() {
this._aircraft = [];
}
x();
}
}
const_prop_assign_pure: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
function Simulator() {
/abc/.index = 1;
this._aircraft = [];
}
(function() {}).prototype.destroy = x();
}
expect: {
function Simulator() {
this._aircraft = [];
}
x();
}
}

View File

@@ -293,3 +293,245 @@ unary: {
bar();
}
}
issue_2629_1: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a();
/*@__PURE__*/ (b());
(/*@__PURE__*/ c)();
(/*@__PURE__*/ d());
}
expect_exact: [
"/* */c();",
]
}
issue_2629_2: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a(1)(2)(3);
/*@__PURE__*/ (b(1))(2)(3);
/*@__PURE__*/ (c(1)(2))(3);
/*@__PURE__*/ (d(1)(2)(3));
(/*@__PURE__*/ e)(1)(2)(3);
(/*@__PURE__*/ f(1))(2)(3);
(/*@__PURE__*/ g(1)(2))(3);
(/*@__PURE__*/ h(1)(2)(3));
}
expect_exact: [
"/* */e(1)(2)(3);",
"/* */f(1)(2)(3);",
"/* */g(1)(2)(3);",
]
}
issue_2629_3: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a.x(1).y(2).z(3);
/*@__PURE__*/ (b.x)(1).y(2).z(3);
/*@__PURE__*/ (c.x(1)).y(2).z(3);
/*@__PURE__*/ (d.x(1).y)(2).z(3);
/*@__PURE__*/ (e.x(1).y(2)).z(3);
/*@__PURE__*/ (f.x(1).y(2).z)(3);
/*@__PURE__*/ (g.x(1).y(2).z(3));
(/*@__PURE__*/ h).x(1).y(2).z(3);
(/*@__PURE__*/ i.x)(1).y(2).z(3);
(/*@__PURE__*/ j.x(1)).y(2).z(3);
(/*@__PURE__*/ k.x(1).y)(2).z(3);
(/*@__PURE__*/ l.x(1).y(2)).z(3);
(/*@__PURE__*/ m.x(1).y(2).z)(3);
(/*@__PURE__*/ n.x(1).y(2).z(3));
}
expect_exact: [
"/* */h.x(1).y(2).z(3);",
"/* */i.x(1).y(2).z(3);",
"/* */j.x(1).y(2).z(3);",
"/* */k.x(1).y(2).z(3);",
"/* */l.x(1).y(2).z(3);",
"/* */m.x(1).y(2).z(3);",
]
}
issue_2629_4: {
options = {
side_effects: true,
}
input: {
(/*@__PURE__*/ x(), y());
(w(), /*@__PURE__*/ x(), y());
}
expect: {
y();
w(), y();
}
}
issue_2629_5: {
options = {
side_effects: true,
}
input: {
[ /*@__PURE__*/ x() ];
[ /*@__PURE__*/ x(), y() ];
[ w(), /*@__PURE__*/ x(), y() ];
}
expect: {
y();
w(), y();
}
}
issue_2638: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/(g() || h())(x(), y());
(/*@__PURE__*/ (a() || b()))(c(), d());
}
expect_exact: [
"/* */x(),y();",
"/* */(a()||b())(c(),d());",
]
}
issue_2705_1: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ new a();
/*@__PURE__*/ (new b());
new (/*@__PURE__*/ c)();
(/*@__PURE__*/ new d());
}
expect_exact: [
"new/* */c;",
]
}
issue_2705_2: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ new a(1)(2)(3);
/*@__PURE__*/ new (b(1))(2)(3);
/*@__PURE__*/ new (c(1)(2))(3);
/*@__PURE__*/ new (d(1)(2)(3));
new (/*@__PURE__*/ e)(1)(2)(3);
(/*@__PURE__*/ new f(1))(2)(3);
(/*@__PURE__*/ new g(1)(2))(3);
(/*@__PURE__*/ new h(1)(2)(3));
}
expect_exact: [
"new/* */e(1)(2)(3);",
"/* */new f(1)(2)(3);",
"/* */new g(1)(2)(3);",
]
}
issue_2705_3: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ new a.x(1).y(2).z(3);
/*@__PURE__*/ new (b.x)(1).y(2).z(3);
/*@__PURE__*/ new (c.x(1)).y(2).z(3);
/*@__PURE__*/ new (d.x(1).y)(2).z(3);
/*@__PURE__*/ new (e.x(1).y(2)).z(3);
/*@__PURE__*/ new (f.x(1).y(2).z)(3);
/*@__PURE__*/ new (g.x(1).y(2).z(3));
new (/*@__PURE__*/ h).x(1).y(2).z(3);
/* */ new (/*@__PURE__*/ i.x)(1).y(2).z(3);
(/*@__PURE__*/ new j.x(1)).y(2).z(3);
(/*@__PURE__*/ new k.x(1).y)(2).z(3);
(/*@__PURE__*/ new l.x(1).y(2)).z(3);
(/*@__PURE__*/ new m.x(1).y(2).z)(3);
(/*@__PURE__*/ new n.x(1).y(2).z(3));
}
expect_exact: [
"new/* */h.x(1).y(2).z(3);",
"/* */new/* */i.x(1).y(2).z(3);",
"/* */new j.x(1).y(2).z(3);",
"/* */new k.x(1).y(2).z(3);",
"/* */new l.x(1).y(2).z(3);",
"/* */new m.x(1).y(2).z(3);",
]
}
issue_2705_4: {
options = {
side_effects: true,
}
input: {
(/*@__PURE__*/ new x(), y());
(w(), /*@__PURE__*/ new x(), y());
}
expect: {
y();
w(), y();
}
}
issue_2705_5: {
options = {
side_effects: true,
}
input: {
[ /*@__PURE__*/ new x() ];
[ /*@__PURE__*/ new x(), y() ];
[ w(), /*@__PURE__*/ new x(), y() ];
}
expect: {
y();
w(), y();
}
}
issue_2705_6: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/new (g() || h())(x(), y());
/* */ new (/*@__PURE__*/ (a() || b()))(c(), d());
}
expect_exact: [
"/* */x(),y();",
"/* */new(/* */a()||b())(c(),d());",
]
}

View File

@@ -1,6 +1,7 @@
strict: {
options = {
pure_getters: "strict",
reduce_funcs: false,
reduce_vars: false,
side_effects: true,
toplevel: true,
@@ -30,6 +31,7 @@ strict: {
strict_reduce_vars: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -58,6 +60,7 @@ strict_reduce_vars: {
unsafe: {
options = {
pure_getters: true,
reduce_funcs: false,
reduce_vars: false,
side_effects: true,
toplevel: true,
@@ -84,6 +87,7 @@ unsafe: {
unsafe_reduce_vars: {
options = {
pure_getters: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -181,10 +185,11 @@ impure_getter_2: {
issue_2110_1: {
options = {
cascade: true,
collapse_vars: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -215,6 +220,7 @@ issue_2110_2: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -247,6 +253,7 @@ set_immutable_1: {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -267,9 +274,10 @@ set_immutable_1: {
set_immutable_2: {
options = {
cascade: true,
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -293,6 +301,7 @@ set_immutable_3: {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -315,9 +324,10 @@ set_immutable_3: {
set_immutable_4: {
options = {
cascade: true,
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -338,11 +348,63 @@ set_immutable_4: {
expect_stdout: true
}
set_immutable_5: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
"use strict";
1..foo += "";
1..foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: true
}
set_immutable_6: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
1..foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: true
}
set_mutable_1: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -364,9 +426,10 @@ set_mutable_1: {
set_mutable_2: {
options = {
cascade: true,
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -385,3 +448,373 @@ set_mutable_2: {
}
expect_stdout: "PASS"
}
issue_2265_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({ ...{} }).p;
({ ...g }).p;
}
expect: {
({ ...g }).p;
}
}
issue_2265_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = {
get b() {
throw 0;
}
};
({...a}).b;
}
expect: {
var a = {
get b() {
throw 0;
}
};
({...a}).b;
}
}
issue_2265_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = {
set b() {
throw 0;
}
};
({...a}).b;
}
expect: {}
}
issue_2265_4: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = { b: 1 };
({...a}).b;
}
expect: {}
}
issue_2313_1: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_2: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_3: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_4: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_5: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x().y;
}
}
issue_2313_6: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x();
}
}
issue_2313_7: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
}
input: {
var a = 0, b = 0;
class foo {
get c() {
a++;
return 42;
}
set c(c) {
b++;
}
}
class bar extends foo {
d() {
super.c++;
if (super.c) console.log(a, b);
}
}
new bar().d();
}
expect: {
var a = 0, b = 0;
class foo {
get c() {
a++;
return 42;
}
set c(c) {
b++;
}
}
class bar extends foo {
d() {
super.c++;
super.c && console.log(a, b);
}
}
new bar().d();
}
expect_stdout: "2 1"
node_version: ">=6"
}
issue_2678: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
var a = 1, c = "FAIL";
(function f() {
(a-- && f()).p;
return {
get p() {
c = "PASS";
}
};
})();
console.log(c);
}
expect: {
var a = 1, c = "FAIL";
(function f() {
(a-- && f()).p;
return {
get p() {
c = "PASS";
}
};
})();
console.log(c);
}
expect_stdout: "PASS"
}

File diff suppressed because it is too large Load Diff

536
test/compress/rename.js Normal file
View File

@@ -0,0 +1,536 @@
mangle_catch: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
ie8: false,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(o){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
ie8: true,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(args){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
ie8: false,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(o){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
ie8: true,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(args){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
ie8: false,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_var_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
ie8: false,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_var_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_1: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
ie8: false,
toplevel: false,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
ie8: true,
toplevel: false,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
ie8: false,
toplevel: true,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_2: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
ie8: false,
toplevel: false,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
ie8: true,
toplevel: false,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
ie8: false,
toplevel: true,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
issue_2120_1: {
rename = true
mangle = {
ie8: false,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (t) {
try {
throw 0;
} catch (a) {
if (t) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
issue_2120_2: {
rename = true
mangle = {
ie8: true,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
function_iife_catch: {
rename = true
mangle = {
ie8: false,
}
input: {
function f(n) {
!function() {
try {
throw 0;
} catch (n) {
var a = 1;
console.log(n, a);
}
}();
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
function_iife_catch_ie8: {
rename = true
mangle = {
ie8: true,
}
input: {
function f(n) {
!function() {
try {
throw 0;
} catch (n) {
var a = 1;
console.log(n, a);
}
}();
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
function_catch_catch: {
rename = true
mangle = {
ie8: false,
}
input: {
var o = 0;
function f() {
try {
throw 1;
} catch (c) {
try {
throw 2;
} catch (o) {
var o = 3;
console.log(o);
}
}
console.log(o);
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_stdout: [
"3",
"undefined",
]
}
function_catch_catch_ie8: {
rename = true
mangle = {
ie8: true,
}
input: {
var o = 0;
function f() {
try {
throw 1;
} catch (c) {
try {
throw 2;
} catch (o) {
var o = 3;
console.log(o);
}
}
console.log(o);
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_stdout: [
"3",
"undefined",
]
}

View File

@@ -17,7 +17,6 @@ return_undefined: {
keep_fnames : false,
hoist_vars : true,
join_vars : true,
cascade : true,
negate_iife : true
};
input: {
@@ -122,3 +121,25 @@ return_undefined: {
}
}
}
return_void: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g() {
h();
}
return g();
}
}
expect: {
function f() {
h();
}
}
}

View File

@@ -187,6 +187,7 @@ dont_screw_try_catch_undefined: {
reduce_vars: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
ie8: true,
unused: true,
@@ -325,3 +326,69 @@ issue_2120_2: {
}
expect_stdout: "PASS"
}
issue_2254_1: {
mangle = {
ie8: false,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(e) {
try {
throw "FAIL";
} catch (t) {
return e;
}
}
}
expect_stdout: "PASS"
}
issue_2254_2: {
mangle = {
ie8: true,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(t) {
try {
throw "FAIL";
} catch (e) {
return t;
}
}
}
expect_stdout: "PASS"
}

View File

@@ -176,6 +176,11 @@ for_sequences: {
// 4
x = (foo in bar);
for (y = 5; false;);
// 5
x = function() {
foo in bar;
};
for (y = 5; false;);
}
expect: {
// 1
@@ -188,6 +193,10 @@ for_sequences: {
// 4
x = (foo in bar);
for (y = 5; false;);
// 5
for (x = function() {
foo in bar;
}, y = 5; false;);
}
}
@@ -243,13 +252,12 @@ negate_iife_for: {
input: {
(function() {})();
for (i = 0; i < 5; i++) console.log(i);
(function() {})();
for (; i < 5; i++) console.log(i);
for (; i < 10; i++) console.log(i);
}
expect: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 5; i++) console.log(i);
for (!function() {}(); i < 10; i++) console.log(i);
}
expect_stdout: true
}
@@ -309,7 +317,7 @@ unsafe_undefined: {
issue_1685: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -333,7 +341,7 @@ issue_1685: {
func_def_1: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -353,7 +361,7 @@ func_def_1: {
func_def_2: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -371,7 +379,7 @@ func_def_2: {
func_def_3: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -393,7 +401,7 @@ func_def_3: {
func_def_4: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -419,7 +427,7 @@ func_def_4: {
func_def_5: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -626,7 +634,7 @@ side_effects: {
side_effects_cascade_1: {
options = {
cascade: true,
collapse_vars: true,
conditionals: true,
sequences: true,
side_effects: true,
@@ -647,7 +655,7 @@ side_effects_cascade_1: {
side_effects_cascade_2: {
options = {
cascade: true,
collapse_vars: true,
side_effects: true,
}
input: {
@@ -669,7 +677,7 @@ side_effects_cascade_2: {
side_effects_cascade_3: {
options = {
cascade: true,
collapse_vars: true,
conditionals: true,
side_effects: true,
}
@@ -684,14 +692,14 @@ side_effects_cascade_3: {
expect: {
function f(a, b) {
!(b += a) && ((b = a) || (b -= a, b ^= a)),
--a;
a--;
}
}
}
issue_27: {
options = {
cascade: true,
collapse_vars: true,
passes: 2,
sequences: true,
side_effects: true,
@@ -713,7 +721,7 @@ issue_27: {
reassign_const: {
options = {
cascade: true,
collapse_vars: true,
sequences: true,
side_effects: true,
}
@@ -738,7 +746,7 @@ reassign_const: {
issue_2062: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
conditionals: true,
side_effects: true,
}
@@ -754,3 +762,124 @@ issue_2062: {
}
expect_stdout: "1"
}
issue_2313: {
options = {
collapse_vars: true,
sequences: true,
side_effects: true,
}
input: {
var a = 0, b = 0;
var foo = {
get c() {
a++;
return 42;
},
set c(c) {
b++;
},
d: function() {
this.c++;
if (this.c) console.log(a, b);
}
}
foo.d();
}
expect: {
var a = 0, b = 0;
var foo = {
get c() {
return a++, 42;
},
set c(c) {
b++;
},
d: function() {
if (this.c++, this.c) console.log(a, b);
}
}
foo.d();
}
expect_stdout: "2 1"
}
cascade_assignment_in_return: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(a, b) {
return a = x(), b(a);
}
}
expect: {
function f(a, b) {
return b(x());
}
}
}
hoist_defun: {
options = {
join_vars: true,
sequences: true,
}
input: {
x();
function f() {}
y();
}
expect: {
function f() {}
x(), y();
}
}
hoist_decl: {
options = {
join_vars: true,
sequences: true,
}
input: {
var a;
w();
var b = x();
y();
for (var c; 0;) z();
var d;
}
expect: {
var a;
w();
var b = x(), c, d;
for (y(); 0;) z();
}
}
for_init_var: {
options = {
join_vars: true,
unused: false,
}
input: {
var a = "PASS";
(function() {
var b = 42;
for (var c = 5; c > 0;) c--;
a = "FAIL";
var a;
})();
console.log(a);
}
expect: {
var a = "PASS";
(function() {
for (var b = 42, c = 5, a; c > 0;) c--;
a = "FAIL";
})();
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -714,6 +714,7 @@ issue_1705_2: {
options = {
dead_code: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -816,3 +817,50 @@ issue_1758: {
}
expect_stdout: "0 3"
}
issue_2535: {
options = {
evaluate: true,
dead_code: true,
switches: true,
}
input: {
switch(w(), 42) {
case 13: x();
case 42: y();
default: z();
}
}
expect: {
w(), 42;
42;
y();
z();
}
}
issue_1750: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a = 0, b = 1;
switch (true) {
case a, true:
default:
b = 2;
case true:
}
console.log(a, b);
}
expect: {
var a = 0, b = 1;
true;
a, true;
b = 2;
console.log(a, b);
}
expect_stdout: "0 2"
}

View File

@@ -59,7 +59,7 @@ template_string_with_constant_expression: {
var foo = `${4 + 4} equals 4 + 4`;
}
expect: {
var foo = `8 equals 4 + 4`;
var foo = "8 equals 4 + 4";
}
}
@@ -89,21 +89,21 @@ template_string_with_predefined_constants: {
var c = `${4**14}`; // 8 in template vs 9 chars - 268435456
}
expect: {
var foo = `This is undefined`;
var bar = `This is NaN`;
var baz = `This is null`;
var foo = "This is undefined";
var bar = "This is NaN";
var baz = "This is null";
var foofoo = `This is ${1/0}`;
var foobar = "This is ${1/0}";
var foobaz = 'This is ${1/0}';
var barfoo = "This is ${NaN}";
var bazfoo = "This is ${null}";
var bazbaz = `This is ${1/0}`;
var barbar = `This is NaN`;
var barbar = "This is NaN";
var barbar = "This is ${0/0}";
var barber = 'This is ${0/0}';
var a = `4194304`;
var b = `16777216`; // Potential for further concatentation
var a = "4194304";
var b = "16777216"; // Potential for further concatentation
var c = `${4**14}`; // Not worth converting
}
}
@@ -123,7 +123,7 @@ template_string_evaluate_with_many_segments: {
}
expect: {
var foo = `Hello ${guest()}, welcome to ${location()}.`;
var bar = `1234567890`;
var bar = "1234567890";
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
var buzz = `1${foobar()}2${foobar()}3${foobar()}`;
}
@@ -159,7 +159,7 @@ template_string_to_normal_string: {
var bar = "Decimals " + `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
}
expect: {
var foo = `This is undefined`;
var foo = "This is undefined";
var bar = "Decimals 1234567890";
}
}
@@ -192,7 +192,7 @@ evaluate_nested_templates: {
var baz = `${`${`${`foo`}`}`}`;
}
expect: {
var baz = `foo`;
var baz = "foo";
}
}
@@ -241,8 +241,8 @@ enforce_double_quotes_and_evaluate: {
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello world`;
var foo = "Hello world";
var bar = "Hello world";
var baz = `Hello ${world()}`;
}
}
@@ -260,8 +260,8 @@ enforce_single_quotes_and_evaluate: {
var baz = `Hello ${world()}`;
}
expect: {
var foo = `Hello world`;
var bar = `Hello world`;
var foo = "Hello world";
var bar = "Hello world";
var baz = `Hello ${world()}`;
}
}
@@ -339,7 +339,7 @@ escape_dollar_curly: {
console.log(`${1-0}\${2-0}$\{3-0}${4-0}`)
console.log(`$${""}{not an expression}`)
}
expect_exact: "console.log(`\\${ beep }`);console.log(`1\\${2-0}\\${3-0}4`);console.log(`\\${not an expression}`);"
expect_exact: 'console.log("${ beep }");console.log("1${2-0}${3-0}4");console.log("${not an expression}");'
}
template_starting_with_newline: {
@@ -400,3 +400,109 @@ issue_1856_ascii_only: {
}
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
}
side_effects: {
options = {
evaluate: true,
side_effects: true,
}
input: {
`t1`;
tag`t2`;
`t${3}`;
tag`t${4}`;
console.log(`
t${5}`);
function f(a) {
`t6${a}`;
a = `t7${a}` & a;
a = `t8${b}` | a;
a = f`t9${a}` ^ a;
}
}
expect: {
tag`t2`;
tag`t${4}`;
console.log("\nt5");
function f(a) {
a &= `t7${a}`;
a = `t8${b}` | a;
a = f`t9${a}` ^ a;
}
}
}
simple_string: {
options = {
computed_props: true,
evaluate: true,
properties: true,
}
input: {
console.log({[`foo`]: 1}[`foo`], `hi` == "hi", `world`);
}
expect: {
console.log([ 1 ][0], true, "world");
}
expect_stdout: "1 true 'world'"
node_version: ">=4"
}
semicolons: {
beautify = {
semicolons: false,
}
input: {
foo;
`bar`;
}
expect_exact: "foo;`bar`\n"
}
regex_1: {
input: {
console.log(`${/a/} ${6/2} ${/b/.test("b")} ${1?/c/:/d/}`);
}
expect_exact: 'console.log(`${/a/} ${6/2} ${/b/.test("b")} ${1?/c/:/d/}`);'
expect_stdout: "/a/ 3 true /c/"
node_version: ">=4"
}
regex_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(`${/a/} ${6/2} ${/b/.test("b")} ${1?/c/:/d/}`);
}
expect: {
console.log("/a/ 3 true /c/");
}
expect_stdout: "/a/ 3 true /c/"
node_version: ">=4"
}
sequence_1: {
input: {
console.log(`${1,2} ${/a/,/b/}`);
}
expect_exact: 'console.log(`${1,2} ${/a/,/b/}`);'
expect_stdout: "2 /b/"
node_version: ">=4"
}
sequence_2: {
options = {
evaluate: true,
side_effects: true,
}
input: {
console.log(`${1,2} ${/a/,/b/}`);
}
expect: {
console.log("2 /b/");
}
expect_stdout: "2 /b/"
node_version: ">=4"
}

View File

@@ -45,9 +45,9 @@ condition_evaluate: {
if (void 0 == null);
}
expect: {
while (!1);
for (; !0;);
if (!0);
while (0);
for (; 1;);
if (1);
}
}
@@ -68,6 +68,7 @@ label_if_break: {
conditionals: true,
dead_code: true,
evaluate: true,
side_effects: true,
}
input: {
L: if (true) {

View File

@@ -1,6 +1,7 @@
typeof_evaluation: {
options = {
evaluate: true
evaluate: true,
typeofs: true,
};
input: {
a = typeof 1;
@@ -44,7 +45,7 @@ typeof_in_boolean_context: {
function f2() { return g(), "Yes"; }
foo();
console.log(1);
var a = !(console.log(2), !0);
var a = !(console.log(2), 1);
foo();
}
}
@@ -57,6 +58,246 @@ issue_1668: {
if (typeof bar);
}
expect: {
if (!0);
if (1);
}
}
typeof_defun_1: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
function f() {
console.log("YES");
}
function g() {
h = 42;
console.log("NOPE");
}
function h() {
console.log("YUP");
}
g = 42;
"function" == typeof f && f();
"function" == typeof g && g();
"function" == typeof h && h();
}
expect: {
function g() {
h = 42;
console.log("NOPE");
}
function h() {
console.log("YUP");
}
g = 42;
console.log("YES");
"function" == typeof g && g();
"function" == typeof h && h();
}
expect_stdout: [
"YES",
"YUP",
]
}
typeof_defun_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
typeofs: true,
}
input: {
var f = function() {
console.log(x);
};
var x = 0;
x++ < 2 && typeof f == "function" && f();
x++ < 2 && typeof f == "function" && f();
x++ < 2 && typeof f == "function" && f();
}
expect: {
var f = function() {
console.log(x);
};
var x = 0;
x++ < 2 && f();
x++ < 2 && f();
x++ < 2 && f();
}
expect_stdout: [
"1",
"2",
]
}
duplicate_defun_arg_name: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
function long_name(long_name) {
return typeof long_name;
}
console.log(typeof long_name, long_name());
}
expect: {
function long_name(long_name) {
return typeof long_name;
}
console.log(typeof long_name, long_name());
}
expect_stdout: "function undefined"
}
duplicate_lambda_arg_name: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
console.log(function long_name(long_name) {
return typeof long_name;
}());
}
expect: {
console.log(function long_name(long_name) {
return typeof long_name;
}());
}
expect_stdout: "undefined"
}
issue_2728_1: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
(function arguments() {
console.log(typeof arguments);
})();
}
expect: {
(function arguments() {
console.log(typeof arguments);
})();
}
expect_stdout: "object"
}
issue_2728_2: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
function arguments() {
return typeof arguments;
}
console.log(typeof arguments, arguments());
}
expect: {
function arguments() {
return typeof arguments;
}
console.log(typeof arguments, arguments());
}
expect_stdout: "function object"
}
issue_2728_3: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
(function() {
function arguments() {
}
console.log(typeof arguments);
})();
}
expect: {
(function() {
function arguments() {
}
console.log("function");
})();
}
expect_stdout: "function"
}
issue_2728_4: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
typeofs: true,
}
input: {
function arguments() {
}
console.log(typeof arguments);
}
expect: {
function arguments() {
}
console.log("function");
}
expect_stdout: "function"
}
issue_2728_5: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
(function arguments(arguments) {
console.log(typeof arguments);
})();
}
expect: {
(function arguments(arguments) {
console.log(typeof arguments);
})();
}
expect_stdout: "undefined"
}
issue_2728_6: {
options = {
evaluate: true,
reduce_vars: true,
typeofs: true,
}
input: {
function arguments(arguments) {
return typeof arguments;
}
console.log(typeof arguments, arguments());
}
expect: {
function arguments(arguments) {
return typeof arguments;
}
console.log(typeof arguments, arguments());
}
expect_stdout: "function undefined"
}

View File

@@ -43,15 +43,6 @@ unicode_string_literals: {
expect_exact: 'var a="6 length unicode character: \\u{101111}";'
}
// Don't escape identifiers below es6 (or in this case double escaped in expect_exact)
unicode_output_es5_surrogates: {
beautify = {ascii_only: true, ecma: 5}
input: {
var \u{10000} = "6 length unicode character: \u{10FFFF}";
}
expect_exact: 'var \u{10000}="6 length unicode character: \\udbff\\udfff";'
}
check_escape_style: {
beautify = {ascii_only: true, ecma: 6}
input: {
@@ -65,20 +56,6 @@ check_escape_style: {
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u{10000}="\\u{10000}";var \\u{2f800}="\\u{100000}";'
}
// Don't escape identifiers below es6, no escaped identifiers support and no \u{} syntax
check_escape_style_es5: {
beautify = {ascii_only: true, ecma: 5}
input: {
var a = "\x01";
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
var \u0100 = "\u0100";
var \u1000 = "\u1000";
var \u{10000} = "\u{10000}"; // Identifier won't be escaped in es 5.1
var \u{2f800} = "\u{100000}"; // Same
}
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \ud800\udc00="\\ud800\\udc00";var \ud87e\udc00="\\udbc0\\udc00";'
}
ID_continue_with_surrogate_pair: {
beautify = {ascii_only: true, ecma: 6}
input: {
@@ -103,18 +80,49 @@ non_escape_2_non_escape: {
expect_exact: 'var µþ="µþ";'
}
non_escape_2_half_escape1: {
beautify = {ascii_only: false, ascii_identifiers: true, ecma: 6}
input: {
var µþ = "µþ";
issue_2242_1: {
beautify = {
ascii_only: false,
}
expect_exact: 'var \\u00b5\\u00fe="µþ";'
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
}
non_escape_2_half_escape2: {
beautify = {ascii_only: true, ascii_identifiers: false, ecma: 6}
input: {
var µþ = "µþ";
issue_2242_2: {
beautify = {
ascii_only: true,
}
expect_exact: 'var µþ="\\xb5\\xfe";'
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
}
issue_2242_3: {
options = {
evaluate: false,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
}
issue_2242_4: {
options = {
evaluate: true,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
}
issue_2569: {
input: {
new RegExp("[\udc42-\udcaa\udd74-\udd96\ude45-\ude4f\udea3-\udecc]");
}
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
}

View File

@@ -88,9 +88,8 @@ yield_before_punctuators: {
})();
function* g1() { (yield) }
function* g2() { [yield] }
function* g3() { return {yield} } // Added return to avoid {} drop
function* g4() { yield, yield; }
function* g5() { (yield) ? yield : yield; }
function* g3() { yield, yield; }
function* g4() { (yield) ? yield : yield; }
}
expect: {
iter = (function*() {
@@ -98,9 +97,8 @@ yield_before_punctuators: {
})();
function* g1() { (yield) }
function* g2() { [yield] }
function* g3() { return {yield} }
function* g4() { yield, yield; }
function* g5() { (yield) ? yield : yield; }
function* g3() { yield, yield; }
function* g4() { (yield) ? yield : yield; }
}
}
@@ -199,3 +197,17 @@ yield_as_ES5_property: {
expect_exact: '"use strict";console.log({yield:42}.yield);'
expect_stdout: "42"
}
issue_2689: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function* y() {
var t = yield x();
return new t();
}
}
expect_exact: "function*y(){return new(yield x())}"
}

View File

@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify;
exports["parse"] = parse;
exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier;

View File

@@ -1,4 +1,4 @@
var a = bar(1+2);
var b = baz(3+9);
print('q' + 'u' + 'x', a, b);
var x = bar(1+2);
var y = baz(3+9);
print('q' + 'u' + 'x', x, y);
foo(5+6);

View File

@@ -0,0 +1,10 @@
function foo() {
return function() {
console.log("PASS");
};
}
(function() {
var f = foo();
f();
})();

View File

@@ -5,11 +5,7 @@
var site = "http://browserbench.org/JetStream";
if (typeof phantom == "undefined") {
// workaround for tty output truncation upon process.exit()
[process.stdout, process.stderr].forEach(function(stream){
if (stream._handle && stream._handle.setBlocking)
stream._handle.setBlocking(true);
});
require("../tools/exit");
var args = process.argv.slice(2);
var debug = args.indexOf("--debug");
if (debug >= 0) {

View File

@@ -10,13 +10,13 @@ function read(path) {
describe("bin/uglifyjs", function () {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("should produce a functional build when using --self", function (done) {
this.timeout(60000);
this.timeout(120000);
var command = uglifyjscmd + ' --self -mc ecma=';
command += semver.satisfies(process.version, ">=4") ? "6" : "5";
command += ',passes=3,keep_fargs=false,unsafe --wrap WrappedUglifyJS';
exec(command, function (err, stdout) {
exec(command, { maxBuffer: 1048576 }, function (err, stdout) {
if (err) throw err;
eval(stdout);
@@ -66,7 +66,7 @@ describe("bin/uglifyjs", function () {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n");
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==\n");
done();
});
});
@@ -195,7 +195,7 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"",
].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n");
@@ -666,6 +666,25 @@ describe("bin/uglifyjs", function () {
return JSON.stringify(map).replace(/"/g, '\\"');
}
});
it("Should include function calls in source map", function(done) {
var command = [
uglifyjscmd,
"test/input/issue-2310/input.js",
"-c",
"--source-map", "url=inline",
].join(" ");
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, [
'function foo(){return function(){console.log("PASS")}}foo()();',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
""
].join("\n"));
done();
});
});
it("Should dump AST as JSON", function(done) {
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
exec(command, function (err, stdout) {
@@ -686,8 +705,8 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should work with --mangle reserved=[]", function (done) {
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=[callback]';
it("Should work with --mangle reserved=[]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]";
exec(command, function (err, stdout) {
if (err) throw err;
@@ -696,8 +715,8 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should work with --mangle reserved=false", function (done) {
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=false';
it("Should work with --mangle reserved=false", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false";
exec(command, function (err, stdout) {
if (err) throw err;
@@ -706,4 +725,22 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should fail with --mangle-props reserved=[in]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --mangle-props reserved=[in]";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.ok(/^Supported options:\n[\s\S]*?\nERROR: `reserved=\[in]` is not a supported option/.test(stderr), stderr);
done();
});
});
it("Should fail with --define a-b", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --define a-b";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr, "Error parsing arguments for 'define': a-b\n");
done();
});
});
});

View File

@@ -14,7 +14,7 @@ describe("comment filters", function() {
it("Should be able to filter commments with the 'some' option", function() {
var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/");
assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/\n");
assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/");
});
it("Should be able to filter comments by passing a function", function() {
@@ -55,12 +55,12 @@ describe("comment filters", function() {
return true;
};
assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/\n");
assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/");
});
it("Should never be able to filter comment5 when using 'some' as filter", function() {
var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */");
assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n");
assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/");
});
it("Should have no problem on multiple calls", function() {

View File

@@ -48,4 +48,196 @@ describe("Comment", function() {
}, fail, tests[i]);
}
});
it("Should handle comment within return correctly", function() {
var result = uglify.minify([
"function unequal(x, y) {",
" return (",
" // Either one",
" x < y",
" ||",
" y < x",
" );",
"}",
].join("\n"), {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function unequal(x, y) {",
" // Either one",
" return x < y || y < x;",
"}",
].join("\n"));
});
it("Should handle comment folded into return correctly", function() {
var result = uglify.minify([
"function f() {",
" /* boo */ x();",
" return y();",
"}",
].join("\n"), {
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"function f() {",
" /* boo */",
" return x(), y();",
"}",
].join("\n"));
});
it("Should not drop comments after first OutputStream", function() {
var code = "/* boo */\nx();";
var ast = uglify.parse(code);
var out1 = uglify.OutputStream({
beautify: true,
comments: "all",
});
ast.print(out1);
var out2 = uglify.OutputStream({
beautify: true,
comments: "all",
});
ast.print(out2);
assert.strictEqual(out1.get(), code);
assert.strictEqual(out2.get(), out1.get());
});
it("Should retain trailing comments", function() {
var code = [
"if (foo /* lost comment */ && bar /* lost comment */) {",
" // this one is kept",
" {/* lost comment */}",
" !function() {",
" // lost comment",
" }();",
" function baz() {/* lost comment */}",
" // lost comment",
"}",
"// comments right before EOF are lost as well",
].join("\n");
var result = uglify.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
});
it("Should correctly preserve new lines around comments", function() {
var tests = [
[
"// foo",
"// bar",
"x();",
].join("\n"),
[
"// foo",
"/* bar */",
"x();",
].join("\n"),
[
"// foo",
"/* bar */ x();",
].join("\n"),
[
"/* foo */",
"// bar",
"x();",
].join("\n"),
[
"/* foo */ // bar",
"x();",
].join("\n"),
[
"/* foo */",
"/* bar */",
"x();",
].join("\n"),
[
"/* foo */",
"/* bar */ x();",
].join("\n"),
[
"/* foo */ /* bar */",
"x();",
].join("\n"),
"/* foo */ /* bar */ x();",
].forEach(function(code) {
var result = uglify.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
});
});
it("Should preserve new line before comment without beautify", function() {
var code = [
"function f(){",
"/* foo */bar()}",
].join("\n");
var result = uglify.minify(code, {
compress: false,
mangle: false,
output: {
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
});
it("Should preserve comments around IIFE", function() {
var result = uglify.minify("/*a*/(/*b*/function(){/*c*/}/*d*/)/*e*/();", {
compress: false,
mangle: false,
output: {
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "/*a*/ /*b*/(function(){/*c*/}/*d*/ /*e*/)();");
});
it("Should output line comments after statements", function() {
var result = uglify.minify([
"x()//foo",
"{y()//bar",
"}",
].join("\n"), {
compress: false,
mangle: false,
output: {
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"x();//foo",
"{y();//bar",
"}",
].join("\n"));
});
});

View File

@@ -1,7 +1,7 @@
var assert = require("assert");
var uglify = require("../node");
describe("Export", function() {
describe("Export/Import", function() {
it("Should parse export directives", function() {
var inputs = [
['export * from "a.js"', ['*'], "a.js"],
@@ -36,4 +36,22 @@ describe("Export", function() {
assert.equal(st.module_name.value, filename);
}
});
it("Should not parse invalid uses of export", function() {
assert.equal(uglify.minify("export").error.message, "Unexpected token: eof (undefined)");
assert.equal(uglify.minify("export;").error.message, "Unexpected token: punc (;)");
assert.equal(uglify.minify("export();").error.message, "Unexpected token: keyword (export)");
assert.equal(uglify.minify("export(1);").error.message, "Unexpected token: keyword (export)");
assert.equal(uglify.minify("var export;").error.message, "Name expected");
assert.equal(uglify.minify("var export = 1;").error.message, "Name expected");
assert.equal(uglify.minify("function f(export){}").error.message, "Invalid function parameter");
});
it("Should not parse invalid uses of import", function() {
assert.equal(uglify.minify("import").error.message, "Unexpected token: eof (undefined)");
assert.equal(uglify.minify("import;").error.message, "Unexpected token: punc (;)");
assert.equal(uglify.minify("var import;").error.message, "Unexpected token: import");
assert.equal(uglify.minify("var import = 1;").error.message, "Unexpected token: import");
assert.equal(uglify.minify("function f(import){}").error.message, "Unexpected token: name (import)");
});
});

View File

@@ -11,7 +11,7 @@ describe("bin/uglifyjs with input file globs", function() {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);\n');
assert.strictEqual(stdout, 'var print=console.log.bind(console);function foo(o){print("Foo:",2*o)}\n');
done();
});
});
@@ -26,7 +26,7 @@ describe("bin/uglifyjs with input file globs", function() {
});
});
it("bin/uglifyjs with multiple input file globs.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2';
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=3';
exec(command, function(err, stdout) {
if (err) throw err;

View File

@@ -2,16 +2,17 @@ var Uglify = require('../../');
var assert = require("assert");
describe("let", function() {
it("Should not produce reserved keywords as variable name in mangle", function(done) {
this.timeout(10000);
this.timeout(30000);
it("Should not produce reserved keywords as variable name in mangle", function() {
// Produce a lot of variables in a function and run it through mangle.
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
for (var i = 0; i < 18000; i++) {
s += "var v" + i + "=0;";
}
s += '}';
var result = Uglify.minify(s, {compress: false});
var result = Uglify.minify(s, {
compress: false
}).code;
// Verify that select keywords and reserved keywords not produced
[
@@ -19,7 +20,7 @@ describe("let", function() {
"let",
"var",
].forEach(function(name) {
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
assert.strictEqual(result.indexOf("var " + name + "="), -1);
});
// Verify that the variable names that appeared immediately before
@@ -30,9 +31,27 @@ describe("let", function() {
"eet", "fet",
"rar", "oar",
].forEach(function(name) {
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
assert.notStrictEqual(result.indexOf("var " + name + "="), -1);
});
});
it("Should quote mangled properties that are reserved keywords", function() {
var s = '"rrrrrnnnnniiiiiaaaaa";';
for (var i = 0; i < 18000; i++) {
s += "v.b" + i + ";";
}
var result = Uglify.minify(s, {
compress: false,
ie8: true,
mangle: {
properties: true,
}
}).code;
[
"in",
"var",
].forEach(function(name) {
assert.notStrictEqual(result.indexOf(name), -1);
assert.notStrictEqual(result.indexOf('v["' + name + '"]'), -1);
});
done();
});
});

View File

@@ -253,13 +253,19 @@ describe("Left-hand side expressions", function () {
// Multiple spreads are not allowed in destructuring array
expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array");
// Spread in obvious object pattern
expect("({...a} = foo)", "Unexpected token: expand (...)");
// Array spread must be last in destructuring declaration
expect("let [ ...x, a ] = o;", "Rest element must be last element");
// Only one spread per destructuring array declaration
expect("let [ a, ...x, ...y ] = o;", "Rest element must be last element");
// Spread in block should not be allowed
expect("{...a} = foo", "Unexpected token: expand (...)");
// Not in standard yet
expect("let foo = {bar: 42}, bar; bar = {...foo}", "Unexpected token: expand (...)");
// Object spread must be last in destructuring declaration
expect("let { ...x, a } = o;", "Rest element must be last element");
// Only one spread per destructuring declaration
expect("let { a, ...x, ...y } = o;", "Rest element must be last element");
});
});

View File

@@ -42,8 +42,15 @@ describe("minify", function() {
original += code;
compressed += result.code;
});
assert.strictEqual(JSON.stringify(cache).slice(0, 20), '{"cname":5,"props":{');
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
assert.strictEqual(JSON.stringify(cache).slice(0, 10), '{"props":{');
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
"var o=console.log.bind(console);",
'function c(n){o("Foo:",2*n)}',
"var a=n(3),b=r(12);",
'o("qux",a,b),c(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
@@ -68,11 +75,54 @@ describe("minify", function() {
original += code;
compressed += result.code;
});
assert.strictEqual(JSON.stringify(cache).slice(0, 28), '{"vars":{"cname":5,"props":{');
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
assert.strictEqual(JSON.stringify(cache).slice(0, 18), '{"vars":{"props":{');
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
"var o=console.log.bind(console);",
'function c(n){o("Foo:",2*n)}',
"var a=n(3),b=r(12);",
'o("qux",a,b),c(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
it("Should avoid mangled names in cache", function() {
var cache = {};
var original = "";
var compressed = "";
[
'"xxxyy";var i={s:1};',
'"xxyyy";var j={t:2,u:3},k=4;',
'console.log(i.s,j.t,j.u,k);',
].forEach(function(code) {
var result = Uglify.minify(code, {
compress: false,
mangle: {
properties: true,
toplevel: true
},
nameCache: cache
});
if (result.error) throw result.error;
original += code;
compressed += result.code;
});
assert.strictEqual(compressed, [
'"xxxyy";var x={x:1};',
'"xxyyy";var y={y:2,a:3},a=4;',
'console.log(x.x,y.y,y.a,a);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
it("Should not parse invalid use of reserved words", function() {
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
assert.strictEqual(Uglify.minify("function super(){}").error.message, "Unexpected token: name (super)");
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
});
describe("keep_quoted_props", function() {
it("Should preserve quotes in object literals", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
@@ -124,6 +174,17 @@ describe("minify", function() {
assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};');
});
it("Should not mangle quoted property within dead code", function() {
var result = Uglify.minify('({ "keep": 1 }); g.keep = g.change;', {
mangle: {
properties: {
keep_quoted: true
}
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g;");
});
});
describe("inSourceMap", function() {
@@ -230,7 +291,7 @@ describe("minify", function() {
var code = result.code;
assert.strictEqual(code, "// comment1 comment2\nbar();");
});
it("should not drop #__PURE__ hint if function is retained", function() {
it("should drop #__PURE__ hint if function is retained", function() {
var result = Uglify.minify("var a = /*#__PURE__*/(function(){ foo(); })();", {
output: {
comments: "all",
@@ -238,7 +299,7 @@ describe("minify", function() {
}
});
var code = result.code;
assert.strictEqual(code, "var a=/*#__PURE__*/function(){foo()}();");
assert.strictEqual(code, "var a=/* */function(){foo()}();");
})
});
@@ -280,4 +341,67 @@ describe("minify", function() {
assert.strictEqual(result.code, "alert({bar:42});");
});
});
describe("duplicated block-scoped declarations", function() {
[
"let a=1;let a=2;",
"let a=1;var a=2;",
"var a=1;let a=2;",
"let[a]=[1];var a=2;",
"let a=1;var[a]=[2];",
"let[a]=[1];var[a]=[2];",
"const a=1;const a=2;",
"const a=1;var a=2;",
"var a=1;const a=2;",
"const[a]=[1];var a=2;",
"const a=1;var[a]=[2];",
"const[a]=[1];var[a]=[2];",
].forEach(function(code) {
it(code, function() {
var result = Uglify.minify(code, {
compress: false,
mangle: false
});
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, code);
result = Uglify.minify(code);
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: a redeclared");
});
});
});
describe("collapse_vars", function() {
it("Should not produce invalid AST", function() {
var code = [
"function f(a) {",
" a = x();",
" return a;",
"}",
"f();",
].join("\n");
var ast = Uglify.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
},
}).ast;
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 2);
assert.strictEqual(ast.body[0].TYPE, "Defun");
assert.strictEqual(ast.body[0].body.length, 2);
assert.strictEqual(ast.body[0].body[0].TYPE, "SimpleStatement");
var stat = ast.body[0].body[0];
Uglify.minify(ast, {
compress: {
sequences: false
},
mangle: false
});
assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()");
});
});
});

View File

@@ -4,7 +4,11 @@ var assert = require("assert");
describe("Object", function() {
it("Should allow objects to have a methodDefinition as property", function() {
var code = "var a = {test() {return true;}}";
assert.equal(Uglify.minify(code).code, "var a={test(){return!0}};");
assert.equal(Uglify.minify(code, {
compress: {
arrows: false
}
}).code, "var a={test(){return!0}};");
});
it("Should not allow objects to use static keywords like in classes", function() {

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