Compare commits

..

663 Commits

Author SHA1 Message Date
Alex Lam S.L
a9eecd844f harmony-v3.0.22 2017-06-30 12:56:56 +08:00
alexlamsl
ed3032e52a Merge branch 'master' into harmony-v3.0.22 2017-06-30 11:24:07 +08:00
Alex Lam S.L
7659ea1d2e v3.0.22 2017-06-30 11:18:34 +08:00
Alex Lam S.L
52cc21d999 remove extraneous ! before AST_Arrow (#2185) 2017-06-30 11:17:58 +08:00
kzc
a938fe5e1f async arrow function IIFE fix (#2184)
fixes #2183
2017-06-30 10:12:42 +08:00
kzc
07a5a57336 fix await parens for property access and calls (#2181)
fixes #2179
2017-06-30 09:14:24 +08:00
Alex Lam S.L
bdeadffbf5 improve usability of name cache under minify() (#2176)
fixes #2174
2017-06-29 12:48:34 +08:00
Alex Lam S.L
945db924fc Merge pull request #2177 from alexlamsl/harmony-v3.0.21
Merging from master for 3.0.21
2017-06-29 02:37:28 +08:00
alexlamsl
087bce508a Merge branch 'master' into harmony-v3.0.21 2017-06-29 00:58:28 +08:00
Alex Lam S.L
5e6f26445f v3.0.21 2017-06-29 00:49:06 +08:00
kzc
fc7e33453f [ES6] document mangle option keep_classnames (#2175) 2017-06-28 23:51:58 +08:00
Alex Lam S.L
d052394621 fix line terminators in template literals (#2173)
fixes #2172
2017-06-28 22:52:29 +08:00
Alex Lam S.L
4d5aeeddfb compress AST_Arrow properly (#2170) 2017-06-28 01:06:30 +08:00
Alex Lam S.L
f0a99125ee improve unsafe_Func (#2171)
- minimise disturbance to `compute_char_frequency()`
- remove extraneous quotation marks
2017-06-27 23:53:42 +08:00
Alex Lam S.L
1e4de2e6d3 parse @global_defs as expressions (#2169)
- let parser rejects non-conformant input
- eliminate need for extraneous parenthesis
2017-06-27 10:31:19 +08:00
Alex Lam S.L
ad139aa34d fix side_effects on AST_Expansion (#2165)
fixes #2163
2017-06-27 01:13:00 +08:00
kzc
26be15f111 update uglify-es keywords in package.json (#2168) 2017-06-27 00:56:01 +08:00
kzc
179f33f08a update doc notes for uglify-es (#2164) 2017-06-26 11:04:22 +08:00
kzc
d260fe9018 more documentation for the ecma option (#2162) 2017-06-26 02:39:14 +08:00
Alex Lam S.L
96f9b8cba3 Merge pull request #2161 from alexlamsl/harmony-v3.0.20
Merging from master for 3.0.20
2017-06-25 17:18:06 +08:00
alexlamsl
11afa816e3 Merge branch 'master' into harmony-v3.0.20 2017-06-25 16:43:44 +08:00
Alex Lam S.L
8b4dcd8f3e v3.0.20 2017-06-25 15:05:05 +08:00
Alex Lam S.L
285401ced8 more tests for #2158 (#2160) 2017-06-25 14:21:48 +08:00
Alex Lam S.L
9db4c42380 fix cascade & collapse on property access of constants (#2158) 2017-06-24 21:30:06 +08:00
Alex Lam S.L
49f3de8397 toplevel shorthand for ecma (#2157) 2017-06-24 19:06:58 +08:00
Alex Lam S.L
94f93ad82d support trailing commas in function parameter lists and calls (#2156)
fixes #2155
2017-06-24 17:34:14 +08:00
Alex Lam S.L
d1f085bce7 add new arrows compress option (#2154)
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.

fixes #2150
2017-06-24 14:45:24 +08:00
Alex Lam S.L
7b95b63ca1 [ES6] support async arrow functions (#2153)
fixes #2102
2017-06-24 05:26:35 +08:00
Alex Lam S.L
94e5e00c03 refactor compute_char_frequency() (#2152)
- minimise maintenance when updating AST
- maximise code sharing between `master` & `harmony`
2017-06-23 20:05:31 +08:00
Alex Lam S.L
dc6bcaa18e synchronise mangle.properties for minify() & test/compress (#2151) 2017-06-23 15:53:13 +08:00
Alex Lam S.L
d58b184835 refactor Compressor.toplevel (#2149) 2017-06-23 13:11:40 +08:00
Alex Lam S.L
137e4c4753 fix unused on AST_Destructuring (#2146) 2017-06-23 13:11:26 +08:00
Alex Lam S.L
b3a57ff019 minimise reduce_vars cloning overhead (#2148) 2017-06-23 06:59:53 +08:00
Alex Lam S.L
3d5bc08185 fix reduce_vars on this (#2145)
fixes #2140
2017-06-23 04:44:57 +08:00
Alex Lam S.L
0692435f01 fix for-in loop parsing (#2144) 2017-06-23 04:14:30 +08:00
Alex Lam S.L
b163b13a0b fix export of keyword and redirection (#2143)
fixes #2141
fixes #2142
2017-06-23 03:49:30 +08:00
Alex Lam S.L
402954bdf3 Merge pull request #2139 from alexlamsl/harmony-v3.0.19
Merging from master for 3.0.19
2017-06-22 05:36:14 +08:00
alexlamsl
f5931866e0 Merge branch 'master' into harmony-v3.0.19 2017-06-22 03:26:49 +08:00
Alex Lam S.L
f67a6b0e43 v3.0.19 2017-06-22 03:24:22 +08:00
Alex Lam S.L
471db8a717 fix inline & unused on AST_Expansion (#2138)
- handle rest parameters
- suppress cases with spread arguments

fixes #2136
2017-06-22 01:39:11 +08:00
Alex Lam S.L
8ba9e4e0da fix toplevel on export (#2137)
fixes #2134
2017-06-22 00:31:17 +08:00
Alex Lam S.L
71556d00b5 correctly parse export of function & class (#2135) 2017-06-21 23:15:39 +08:00
Alex Lam S.L
8709753bfb fix mangle on export (#2133)
- `export default ...`
- `export` with `AST_Destructuring`

fixes #2129
2017-06-21 14:22:09 +08:00
Alex Lam S.L
db877e8729 fix drop_unused() accounting of symbols within export function (#2132)
fixes #2131
2017-06-21 12:32:58 +08:00
Alex Lam S.L
11923e3ae8 reject non-toplevel import/export (#2128)
fixes #2124
2017-06-21 03:18:48 +08:00
Alex Lam S.L
62d1fbf645 support export statements properly (#2126)
- mangle & compress correctly with `toplevel`
- retain non-toplevel import/export
- parse & output `export { variable as name }`
- remove extraneous spaces from `beautify`


fixes #2038
fixes #2124
2017-06-21 00:51:36 +08:00
Alex Lam S.L
343ea326c2 ensure mangling works if catch reuses a scope variable (#2123)
fixes #2120
2017-06-20 02:14:05 +08:00
kzc
849ba79dee retain names in export default class and function (#2122)
fixes #2121
2017-06-19 14:30:59 +08:00
Alex Lam S.L
a298bcce02 Merge pull request #2119 from alexlamsl/harmony-v3.0.18
Merging from master for 3.0.18
2017-06-18 17:16:46 +08:00
alexlamsl
daaf1273fa Merge branch 'master' into harmony-v3.0.18 2017-06-18 15:49:49 +08:00
Alex Lam S.L
1c150c632f v3.0.18 2017-06-18 15:01:20 +08:00
Alex Lam S.L
0a0f4f5591 make defensive copies when inline (#2116)
fixes #2114
2017-06-17 14:32:37 +08:00
Alex Lam S.L
931daa85bf fix loss of context in collapse_vars & cascade (#2112)
fixes #2110
2017-06-16 21:18:43 +08:00
Alex Lam S.L
00e4f7b3c1 in-place tigten_body() (#2111)
By reducing copies of `AST_Node` arrays, we should be able to reduce:
- memory pressure
- potential bugs caused by multiple references in AST
- duplicated executions of `OPT()`
2017-06-16 19:19:54 +08:00
Alex Lam S.L
11e63bc335 correctly determine scope of AST_This (#2109)
fixes #2107
2017-06-16 14:54:46 +08:00
kzc
3fa862ce19 support shorthand property named "async" (#2108) 2017-06-16 12:18:18 +08:00
Alex Lam S.L
33405bb24b enforce inline scope restriction (#2106)
fixes #2105
2017-06-16 03:21:38 +08:00
Alex Lam S.L
370f2cc906 Merge pull request #2104 from alexlamsl/harmony-v3.0.17
Merging from master for 3.0.17
2017-06-15 23:07:22 +08:00
alexlamsl
78cf35f89c Merge branch 'master' into harmony-v3.0.17 2017-06-15 19:01:36 +08:00
Alex Lam S.L
57dc4fb32f v3.0.17 2017-06-15 18:59:37 +08:00
Alex Lam S.L
b85a358deb suppress inline of this (#2103)
fixes #2101
2017-06-15 12:14:16 +08:00
kzc
100e18305d first cut of async/await (#2098)
- async arrow functions not yet supported


fixes #1789
2017-06-15 06:15:48 +08:00
Alex Lam S.L
43697958f3 avoid intermittent test time-out failures (#2100) 2017-06-15 04:47:57 +08:00
Alex Lam S.L
3f961bbba0 compute uses_arguments correctly in figure_out_scope() (#2099)
fixes #2097
2017-06-15 03:28:26 +08:00
Alex Lam S.L
7cc03d4d40 fix parsing of expect_stdout (#2096)
fixes #2095
2017-06-15 01:26:49 +08:00
Alex Lam S.L
0a1e523cd5 fix parsing of expect_stdout (#2096)
fixes #2095
2017-06-15 01:00:03 +08:00
Alex Lam S.L
c28056d7ed Merge pull request #2094 from alexlamsl/harmony-v3.0.16
Merging from master for 3.0.16
2017-06-14 19:25:21 +08:00
alexlamsl
8af362ed57 Merge branch 'master' into harmony-v3.0.16 2017-06-14 17:09:30 +08:00
Alex Lam S.L
4231f7323e v3.0.16 2017-06-14 16:45:09 +08:00
Alex Lam S.L
68138f2281 fix reduce_vars on AST_Arrow (#2091)
fixes #2090
2017-06-14 16:40:37 +08:00
kzc
da2de350c3 add comment about quote_style and gzip (#2092) 2017-06-14 12:23:03 +08:00
Alex Lam S.L
41beae4dd7 cache web assets between CI runs (#2089)
- skip `test/jetstream.js` for `node@0.12`
2017-06-14 11:53:10 +08:00
Ziad El Khoury Hanna
82db9188ac fix CLI parsing of --source-map content (#2088)
fixes #2082
2017-06-13 16:30:46 +08:00
Alex Lam S.L
3dc9e140e4 add Node.js 8 to Travis CI (#2086)
- explicitly terminate `test/jetstream.js` upon completion
- log verbose output from `test/benchmark.js` & `test/jetstream.js`
- remove obsolete workaround for Travis CI
2017-06-13 06:21:16 +08:00
Alex Lam S.L
fed0096556 allow expect_stdout to specify Error (#2087) 2017-06-13 04:57:26 +08:00
Alex Lam S.L
2bdc8802dd fix variable accounting in inline (#2085)
fixes #2084
2017-06-13 01:40:14 +08:00
Alex Lam S.L
5ef7cb372a suppress false positives for-in loops (#2080)
fixes #2079
2017-06-10 13:55:17 +08:00
Alex Lam S.L
4ad7b1dae4 fix portability of sandbox.run_code() on Node.js 0.1x (#2078) 2017-06-10 01:08:58 +08:00
Alex Lam S.L
9186859cb7 fix non-string parameters (#2076)
`Stream.write()` is not as versatile as `console.log()`
2017-06-10 00:11:40 +08:00
Alex Lam S.L
47c0713747 report test/ufuzz.js failures in process.stderr (#2074) 2017-06-09 15:56:28 +08:00
Alex Lam S.L
293c566d6c marshal mangle[.properties].reserved from non-Array values (#2072) 2017-06-09 04:29:12 +08:00
Alex Lam S.L
9c306406f1 fix iteration over object with inherited properties (#2068)
fixes #2055
2017-06-08 03:27:03 +08:00
Alex Lam S.L
9db0695b10 fix cascade on multi-branch evaluations (#2067)
Partially reverts #2059 as this has better coverage and performance.

fixes #2062
2017-06-07 19:52:01 +08:00
Alex Lam S.L
a7971f4e34 fix unused crash with top-level AST_Var (#2066)
fixes #2063
2017-06-07 19:12:35 +08:00
Alex Lam S.L
f2af093402 fix CLI output corruption (#2061)
Using `console.error()` & `console.log()` result in inconsistent formatting across Node.js versions.

Avoid this issue by directly writing to `process.stderr` & `process.stdout` instead.

Miscellaneous
- prettify invalid option listing
2017-06-07 04:25:32 +08:00
Alex Lam S.L
b9ad53d1ab fix inline handling of AST_Call.args (#2059) 2017-06-06 22:55:25 +08:00
Alex Lam S.L
b0eab71470 implement test/jetstream.js --debug (#2058) 2017-06-06 19:28:12 +08:00
Alex Lam S.L
3493a182b2 implement function inlining (#2053)
- empty body
- single `AST_Return`
- single `AST_SimpleStatement`
- avoid `/*#__PURE__*/`

Miscellaneous
- enhance single-use function substitution

fixes #281
2017-06-06 05:49:53 +08:00
Alex Lam S.L
27c5284d3d workaround webkit parsing error (#2056)
apply `webkit` to jetstream tests
2017-06-06 04:06:42 +08:00
Alex Lam S.L
540220b91b fix AST_Function scope invariance (#2052)
improve function name hack in `run_code()`
2017-06-04 19:27:43 +08:00
kzc
82fefc5d29 fix class expression statements (#2051)
- class expression statements require parentheses
- allow unused class expression statements to be dropped

fixes #1782
closes #1784
2017-06-04 02:45:26 +08:00
kzc
753932b302 drop unused arrow functions (#2050) 2017-06-04 00:20:46 +08:00
Alex Lam S.L
84634da4b5 add tests for AST_SymbolAccessor (#2049) 2017-06-03 16:08:10 +08:00
Alex Lam S.L
1743621889 clean up lib/parse.js (#2047)
- remove unused definitions
- replace `array_to_hash()`
2017-06-03 14:00:59 +08:00
Alex Lam S.L
1edbd6556f fix beautify whitespace output within AST_Destructuring (#2046)
fixes #2044
2017-06-02 18:50:39 +08:00
kzc
f330ab743a better document behavior of unsafe_Func (#2043) 2017-06-02 12:07:17 +08:00
Alex Lam S.L
888a321417 Merge pull request #2042 from alexlamsl/harmony-v3.0.15
Merging from master for 3.0.15
2017-06-01 19:28:30 +08:00
alexlamsl
ee5c03f7f1 Merge branch 'master' into harmony-v3.0.15 2017-06-01 18:26:09 +08:00
Alex Lam S.L
4377e932ca v3.0.15 2017-06-01 18:12:38 +08:00
Alex Lam S.L
bac14ba881 fix non-identifier getter/setter name (#2041)
fixes #2040
2017-06-01 18:11:16 +08:00
Alex Lam S.L
ec095ed647 whitelist unsafe evaluate candidates (#2039)
- all arguments may accept constant values
- return constant value
- free of side effects
- available & identical across locales and runtime environments
2017-06-01 04:33:05 +08:00
Alex Lam S.L
17e73121fa enhance unsafe evaluate (#2037) 2017-06-01 00:56:28 +08:00
kzc
0cb75089f0 document safari10 mangle option (#2035) 2017-05-31 23:16:20 +08:00
kzc
f71e8fd948 reformat mangle options section of README (#2036) 2017-05-31 21:52:43 +08:00
Alex Lam S.L
a1647ee0c5 Merge pull request #2034 from alexlamsl/harmony-v3.0.14
Merging from master for 3.0.14
2017-05-31 12:44:58 +08:00
alexlamsl
c814060b4a Merge branch 'master' into harmony-v3.0.14 2017-05-31 11:42:54 +08:00
Alex Lam S.L
3e62faa64f v3.0.14 2017-05-31 11:34:51 +08:00
Alex Lam S.L
e9645e017f introduce unsafe_Func (#2033)
Separate flag for #203 functionality.
2017-05-31 03:38:00 +08:00
Alex Lam S.L
55b5f2a8aa widen CLI parse error code fragment displayed (#2032)
fixes #2030
2017-05-31 01:56:52 +08:00
Alex Lam S.L
303293e4aa fix side_effects on AST_Class (#2031)
fixes #2028
2017-05-31 01:44:29 +08:00
Alex Lam S.L
23265ac253 mangle destructuring function parameters (#2029)
fixes #2025
2017-05-30 23:41:55 +08:00
Alex Lam S.L
0cc6dedccc fix block elimination (#2023)
fixes #1664
fixes #1672
2017-05-30 14:59:54 +08:00
kzc
ec63588496 fix compress of IIFE with destructuring args (#2022) 2017-05-30 13:17:06 +08:00
Alex Lam S.L
c2e471e3ad fix if_return on block-scoped variables (#2021)
fixes #1317
2017-05-29 18:08:08 +08:00
Alex Lam S.L
ee23a84e14 Merge pull request #2020 from alexlamsl/harmony-v3.0.13
Merging from master for 3.0.13
2017-05-29 12:24:38 +08:00
alexlamsl
520da57fdc Merge branch 'master' into harmony-v3.0.13 2017-05-29 10:58:05 +08:00
Alex Lam S.L
4e0a22e5c8 v3.0.13 2017-05-29 10:52:13 +08:00
Alex Lam S.L
1aa38051fb better fix for #512 & #2010 (#2019)
- remove duplicated functionalities
- fix similar issue with `else`
2017-05-29 10:51:41 +08:00
Alex Lam S.L
e62b879b48 display default values in --help options (#2018) 2017-05-28 22:57:20 +08:00
Alex Lam S.L
c6c9f4f5a8 implement --help options (#2017) 2017-05-28 18:21:44 +08:00
Alex Lam S.L
fec14379f6 improve CLI usability (#2016)
Report supported options upon invalid option syntax.

fixes #1883
2017-05-28 04:09:40 +08:00
Alex Lam S.L
e5e0ce0b42 Merge pull request #2014 from alexlamsl/harmony-v3.0.12
Merging from master for 3.0.12
2017-05-28 00:08:08 +08:00
Alex Lam S.L
79131cd647 extend node_version range on applicable tests (#2015) 2017-05-27 22:18:28 +08:00
alexlamsl
94d2aeee89 fix block-scoped function for ES6
fixes #1903
2017-05-27 19:28:07 +08:00
alexlamsl
aa835eb0f6 Merge branch 'master' into harmony-v3.0.12 2017-05-27 18:12:10 +08:00
Alex Lam S.L
c3f14a1481 v3.0.12 2017-05-27 18:08:09 +08:00
Alex Lam S.L
7b13159cda fix hoist_funs on block-scoped function under "use strict" (#2013)
Technically not part of ES5, but commonly used code exists in the wild.
2017-05-27 17:44:59 +08:00
Alex Lam S.L
95094b9c22 fix if_return on AST_Defun (#2010)
Previous fiix for #1052 perturbs declaration order of functions which leads to incorrect behaviour under "use strict".
2017-05-27 13:41:49 +08:00
kzc
1ff8e9dd38 clarify what --mangle-props does (#2012) 2017-05-27 13:17:30 +08:00
kzc
78309a293d better document mangle properties options (#2009) 2017-05-27 02:28:43 +08:00
kzc
695e182d59 fix and expand --mangle-props documentation (#2008)
fixes #2007
2017-05-27 01:25:51 +08:00
Alex Lam S.L
dc33facfcb fix dead_code on block-scoped function under "use strict" (#2006)
Technically not part of ES5, but commonly used code exists in the wild.
2017-05-26 16:08:51 +08:00
Alex Lam S.L
39d4d7e20a fix export related issues (#2005)
- `mangle` non-exported names
- `unused` on `export` of `function`
- `hoist_funs` on `export`
- `export default`
  - prohibit definition statements
  - parse `AST_Defun` properly
  - drop only unused class and function names


fixes #2001
fixes #2004
2017-05-26 13:35:40 +08:00
Alex Lam S.L
c70fb60384 clean up lib/scope.js (#2003)
fixes #2004
2017-05-26 03:58:35 +08:00
Alex Lam S.L
02811ce35e fix issues related to export & function (#2002)
- `unused` function names
- confusion with function call syntax

fixes #2001
2017-05-26 03:12:52 +08:00
Alex Lam S.L
793d61499b report timing breakdown (#2000)
fix corner cases with `sourceMap`

fixes #1998
2017-05-25 07:15:55 +08:00
Alex Lam S.L
a277fe168d ensure new line after describe_ast() (#1999) 2017-05-25 02:32:36 +08:00
Alex Lam S.L
c988e5f4d6 remove AST_ArrowParametersOrSeq (#1997) 2017-05-24 17:45:18 +08:00
Alex Lam S.L
7d3b941e6e reinstate describe_ast() on CLI (#1996)
fixes #1995
2017-05-24 02:30:09 +08:00
Alex Lam S.L
075b648bb1 Merge pull request #1994 from alexlamsl/harmony-v3.0.11
Merging from master for 3.0.11
2017-05-24 00:04:47 +08:00
alexlamsl
37e549ff4f Merge branch 'master' into harmony-v3.0.11 2017-05-23 22:29:04 +08:00
Alex Lam S.L
e95052a423 v3.0.11 2017-05-23 22:26:59 +08:00
Alex Lam S.L
e667f0acb8 fix source map offset (#1993)
Account for whitespace insertions.

fixes #505
fixes #890
2017-05-23 20:25:48 +08:00
kzc
7bcb442e4c fix destructuring bugs in mangle and compress (#1992)
- destructuring mangle
- destructuring array default values

fixes #1335
2017-05-23 02:53:01 +08:00
kzc
a658cd84a5 fix destructuring of non string keys (#1989) 2017-05-22 16:38:03 +08:00
kzc
69ac794bc8 add another minify() options example (#1988) 2017-05-22 12:19:07 +08:00
Alex Lam S.L
efdb65913b improve usability of global_defs in minify() (#1987)
Use `@key` to `parse()` string value as `AST_Node`.

fixes #1986
2017-05-22 01:38:43 +08:00
kzc
a1dedeb3ce more refinement of minify() documentation (#1983) 2017-05-21 04:55:03 +08:00
Alex Lam S.L
5b22334f3b Merge pull request #1982 from alexlamsl/harmony-v3.0.10
Merging from master for 3.0.10
2017-05-21 03:23:59 +08:00
alexlamsl
a3053c537a Merge branch 'master' into harmony-v3.0.10 2017-05-21 01:36:38 +08:00
Alex Lam S.L
d3c4a8e9e7 v3.0.10 2017-05-21 01:30:17 +08:00
kzc
d6f77a6352 update keywords in package.json (#1981) 2017-05-20 22:10:51 +08:00
kzc
7e164aba8f add "es5" to package.json keywords (#1980) 2017-05-20 22:09:50 +08:00
kzc
22aedef849 document minify() option toplevel (#1979) 2017-05-20 22:09:21 +08:00
Alex Lam S.L
58fae7dc07 enhance if_return to handle return void... (#1977)
fixes #512
2017-05-20 15:58:46 +08:00
Alex Lam S.L
a2172e1a99 fix parsing of yield as object key (#1976)
fixes #1974
2017-05-20 13:11:37 +08:00
kzc
5bf8d7e949 document 3.x minify() does not throw errors (#1975) 2017-05-20 10:49:35 +08:00
kzc
1df9d06f4a document minify warnings and add an error example (#1973) 2017-05-19 17:20:21 +08:00
Alex Lam S.L
9a074c2637 Merge pull request #1972 from alexlamsl/harmony-v3.0.9
Merging from master for 3.0.9
2017-05-19 10:38:45 +08:00
alexlamsl
02b14528fa Merge branch 'master' into harmony-v3.0.9 2017-05-19 09:51:00 +08:00
Alex Lam S.L
3408fc9d32 v3.0.9 2017-05-19 09:35:26 +08:00
Alex Lam S.L
eae26756f1 introduce unsafe_regexp (#1970)
fixes #1964
2017-05-19 09:06:29 +08:00
Alex Lam S.L
3db2001633 suppress unused on block variables (#1969)
fixes #1968
2017-05-19 00:28:19 +08:00
Alex Lam S.L
aaba482e48 Merge pull request #1967 from alexlamsl/harmony-v3.0.8
Merging from master for 3.0.8
2017-05-18 16:02:29 +08:00
alexlamsl
5f29fced0a Merge branch 'master' into harmony-v3.0.8 2017-05-18 14:54:18 +08:00
Alex Lam S.L
43add9416b v3.0.8 2017-05-18 14:49:40 +08:00
Alex Lam S.L
efcf167e5e make expect_stdout node version specific (#1963)
... via semver string on `node_version` label.
2017-05-18 11:28:35 +08:00
Kara
6ed90913ca fix docs for side_effects flag to reflect current behavior (#1966) 2017-05-18 10:51:49 +08:00
kzc
b1b918e6d6 better extends paren fix (#1962) 2017-05-18 02:36:29 +08:00
Alex Lam S.L
569c21e952 improve RegExp handling (#1959)
- remove `options.output.unescape_regexps`
- preserve original pattern whenever possible

fixes #54
fixes #1929
2017-05-17 20:10:50 +08:00
Alex Lam S.L
87c3a2c0ce remove space_colon (#1960)
Always emit space after colon when `options.output.beautify` is enabled.
2017-05-17 14:07:34 +08:00
Rob Garrison
baef8bf050 update output options in readme (#1958) 2017-05-17 11:54:46 +08:00
alexlamsl
0813c5316f remove Travis CI badge 2017-05-17 10:32:59 +08:00
kzc
ebb469e4cd fix class extends expression (#1956) 2017-05-17 03:29:25 +08:00
kzc
c22d26b483 support export default of anonymous functions and classes (#1954) 2017-05-17 03:28:24 +08:00
Alex Lam S.L
f751e64d49 Merge pull request #1951 from alexlamsl/harmony-v3.0.7
Merging from master for 3.0.7
2017-05-17 01:03:55 +08:00
alexlamsl
60c56a24b9 Merge branch 'master' into harmony-v3.0.7 2017-05-16 20:02:30 +08:00
Alex Lam S.L
c88139492d v3.0.7 2017-05-16 19:59:40 +08:00
Alex Lam S.L
cb45886512 export TreeTransformer (#1950)
- link to existing documentation on `TreeWalker` & `TreeTransformer`
- fix Travis build failures

fixes #1949
2017-05-16 19:59:05 +08:00
Alex Lam S.L
01f23cf5a1 Merge pull request #1948 from alexlamsl/harmony-v3.0.6
Merging from master for 3.0.6
2017-05-16 13:26:45 +08:00
alexlamsl
99fb3e8f0d Merge branch 'master' into harmony-v3.0.6 2017-05-16 06:48:23 +08:00
Alex Lam S.L
050474ab44 v3.0.6 2017-05-16 06:38:58 +08:00
Alex Lam S.L
f6c805ae1d print package name alongside version in CLI (#1946)
fixes #1945
2017-05-16 06:34:32 +08:00
Alex Lam S.L
9464d3c20f fix parsing of property access after new line (#1944)
Account for comments when detecting property access in `tokenizer`.

fixes #1943
2017-05-16 05:40:49 +08:00
alexlamsl
f18abd1b9c minor fixes to README.md 2017-05-16 01:33:01 +08:00
kzc
3be06ad085 reorg README for 3.x (#1942) 2017-05-16 01:12:00 +08:00
Alex Lam S.L
265008c948 improve keyword-related parser errors (#1941)
fixes #1937
2017-05-15 23:02:55 +08:00
Alex Lam S.L
756c9aa7dc keep minify() options in sync (#1940) 2017-05-15 20:29:48 +08:00
Alex Lam S.L
07d6bfd707 Merge pull request #1939 from alexlamsl/harmony-v3.0.5
Merging from master for 3.0.5
2017-05-15 19:48:00 +08:00
alexlamsl
81243c4e71 Merge branch 'master' into harmony-v3.0.5 2017-05-15 18:58:54 +08:00
alexlamsl
cd6e849555 Revert "remove support for const (#1910)"
This reverts commit c391576d52.
2017-05-15 18:38:16 +08:00
Alex Lam S.L
ff526be61d v3.0.5 2017-05-15 11:37:14 +08:00
Alex Lam S.L
e005099fb1 fix & improve coverage of estree (#1935)
- fix `estree` conversion of getter/setter
- fix non-directive literal in `to_mozilla_ast()`
- revamp `test/mozilla-ast.js`
  - reuse `test/ufuzz.js` for code generation
  - use `acorn.parse()` for creating `estree`
- extend `test/ufuzz.js` for `acorn` workaround
  - catch variable redefinition
  - non-trivial literal as directive
  - adjust options for tolerance

Miscellaneous
- optional semi-colon when parsing directives

fixes #1914
closes #1915
2017-05-15 02:37:53 +08:00
kzc
504a436e9d Tweak README Notes (#1934) 2017-05-14 02:12:14 +08:00
Alex Lam S.L
3ca902258c fix bugs with getter/setter (#1926)
- `reduce_vars`
- `side_effects`
- property access for object
- `AST_SymbolAccessor` as key names

enhance `test/ufuzz.js`
- add object getter & setter
  - property assignment to setter
  - avoid infinite recursion in setter
- fix & adjust assignment operators
  - 50% `=`
  - 25% `+=`
  - 2.5% each for the rest
- avoid "Invalid array length"
- fix `console.log()`
  - bypass getter
  - curb recursive reference
- deprecate `-E`, always report runtime errors
2017-05-14 02:10:34 +08:00
kzc
91de285166 uglify-es: update homepage in package.json (#1933)
to point to harmony branch on github
2017-05-14 00:25:06 +08:00
kzc
4d8f289eb0 fix export default expression; (#1932) 2017-05-13 12:56:46 +08:00
olsonpm
fd0951231c document 3 max passes (#1928) 2017-05-13 12:54:32 +08:00
olsonpm
9e29b6dad2 clarify wording (#1931) 2017-05-13 12:54:01 +08:00
Alex Lam S.L
c391576d52 remove support for const (#1910)
As this is not part of ES5.
2017-05-12 14:57:41 +08:00
Alex Lam S.L
ac73c5d421 avoid arguments and eval in reduce_vars (#1924)
fixes #1922
2017-05-12 12:34:55 +08:00
olsonpm
547f41beba add documentation for side_effects & [#@]__PURE__ (#1925) 2017-05-12 12:29:55 +08:00
Alex Lam S.L
945ba64160 Merge pull request #1923 from alexlamsl/harmony-v3.0.4
Merging from master for 3.0.4
2017-05-12 06:52:21 +08:00
Anthony Van de Gejuchte
c699200398 Make sure globals can be accessed from the browser (#1920)
Note: no tests as there are no integration tests
2017-05-12 05:50:35 +08:00
alexlamsl
daf44f2b21 Merge branch 'master' into harmony-v3.0.4 2017-05-12 05:13:11 +08:00
Alex Lam S.L
daaefc17b9 v3.0.4 2017-05-12 04:52:39 +08:00
Alex Lam S.L
1d407e761e fix invalid transform on const (#1919)
- preserve (re)assignment to `const` for runtime error
- suppress `cascade` on `const`, as runtime behaviour is ill-defined
2017-05-12 04:51:44 +08:00
kzc
2b44f4ae30 update README (#1918) 2017-05-12 03:36:33 +08:00
Alexis Tyler
e51c3541da fix typo (#1913) 2017-05-11 20:24:33 +08:00
Alex Lam S.L
3bf194684b update documentation (#1909)
- clarify options on `--source-map`
- fix `minify()` examples

fixes #1905
2017-05-11 17:50:50 +08:00
Gyusun Yeom
fcd90db30d fix safari syntax error - declare twice (#1851)
To avoid Safari bug, scope of for loop should enclose parent scope variables.


fixes #1753
2017-05-11 16:48:43 +08:00
Alex Lam S.L
e2888bdc43 Merge pull request #1901 from alexlamsl/harmony-v3.0.3
Merging from master for 3.0.3
2017-05-10 14:26:58 +08:00
alexlamsl
fb50b7b627 Merge branch 'master' into harmony-v3.0.3 2017-05-10 11:52:59 +08:00
Alex Lam S.L
aae7d49d0c v3.0.3 2017-05-10 11:45:03 +08:00
kzc
9d59c693c2 fix for-of loop with const iterator (#1899) 2017-05-10 11:36:03 +08:00
kzc
0459af2ecc Update issue template: change harmony to uglify-es (#1900) 2017-05-10 11:07:54 +08:00
kzc
04f2344efc Remove unnecessary git clone instructions in README (#1897) 2017-05-10 11:06:50 +08:00
kzc
6ddb5bd94d Remove incorrect git clone instructions from uglify-es README (#1896) 2017-05-10 11:06:22 +08:00
kzc
bad9d5cf88 Change harmony to uglify-es in master README (#1895) 2017-05-10 05:07:45 +08:00
kzc
eda49605c5 Have harmony docs use uglify-es package name. (#1894) 2017-05-10 04:41:09 +08:00
Alex Lam S.L
a0f5f862df gracefully handle non-Error being thrown (#1893) 2017-05-10 04:20:59 +08:00
Alex Lam S.L
1e9ef17e32 Merge pull request #1892 from alexlamsl/harmony-v3.0.2
Merging from master for 3.0.2
2017-05-10 03:14:45 +08:00
Alex Lam S.L
41996be86f extend test timeout
Travis has gone a lot slower recently, and most test failures are due to time-out on this particular test.
2017-05-10 02:43:12 +08:00
alexlamsl
222100ea4c Merge branch 'master' into harmony-v3.0.2 2017-05-10 01:57:32 +08:00
Alex Lam S.L
5fd8244a2e v3.0.2 2017-05-10 01:52:00 +08:00
Alex Lam S.L
93db48a317 rename package 2017-05-10 01:46:55 +08:00
Alex Lam S.L
2944e3df7d fix collapse_vars on destructuring declarations (#1889)
fixes #1886
2017-05-09 17:44:28 +08:00
Alex Lam S.L
c14e280585 print error stack in CLI (#1890) 2017-05-09 16:36:44 +08:00
Alex Lam S.L
bc3fa78e8c mention minify().error 2017-05-09 16:09:48 +08:00
Alex Lam S.L
8c7c107765 update minify() usage in test/ufuzz.js (#1888)
fixes #1887
2017-05-09 15:58:46 +08:00
Alex Lam S.L
e0ae8da089 Merge pull request #1885 from alexlamsl/harmony-v3.0.1
Merging from master for 3.0.1
2017-05-09 02:49:28 +08:00
alexlamsl
81f1311b24 Merge branch 'master' into harmony-v3.0.1 2017-05-09 02:10:06 +08:00
Alex Lam S.L
2433bb4e52 fix Unicode handling in parser (#1884)
There was an implicit assumption that first character within surrogate header range implies the next character must form a surrogate pair, which is not necessarily true.
2017-05-09 01:58:31 +08:00
kzc
3dd328dce3 [3.x] fix documentation for beautify options (#1882)
- use underscores rather than dashes.
2017-05-08 23:06:56 +08:00
Alex Lam S.L
014f428153 v3.0.1 2017-05-08 07:05:57 +08:00
Alex Lam S.L
a3b2eb75bd return Error from minify() (#1880)
Have `minify()` return `Error` in `result.error` rather than throwing it.
2017-05-08 07:05:19 +08:00
Alex Lam S.L
da295de82b support dumping AST (#1879)
Re-order `AST_Binary` properties to make dump more readable.

closes #769
2017-05-08 06:23:01 +08:00
Alex Lam S.L
4f8ca4626e deprecate low level API (#1877)
fixes #1872
2017-05-08 03:24:42 +08:00
Alex Lam S.L
e54748365c support minify() output as AST (#1878)
- `options.output.ast` (default `false`)
- `options.output.code` (default `true`)
2017-05-08 02:11:45 +08:00
Alex Lam S.L
3fac29a017 Merge pull request #1876 from alexlamsl/harmony-v3.0.0
Merging from master for 3.0.0
2017-05-08 01:44:07 +08:00
alexlamsl
b4c18f6b83 Merge branch 'master' into harmony-v3.0.0 2017-05-07 15:34:16 +08:00
Alex Lam S.L
2d99d06601 update documentation
Remove deprecated CLI option
2017-05-07 03:02:46 +08:00
Alex Lam S.L
98cf95e5b5 fix test for #1865 (#1873) 2017-05-07 02:56:02 +08:00
Alex Lam S.L
7313465cba v3.0.0 2017-05-06 23:51:10 +08:00
Alex Lam S.L
2c7ee956fd fix unsafe on evaluate of reduce_vars (#1870)
Determine if variables with non-constant values can escape and be modified.

fixes #1865
2017-05-06 23:18:55 +08:00
Alex Lam S.L
ecf3563c45 kill opera (#1869) 2017-05-06 17:42:07 +08:00
Alex Lam S.L
dee5a27516 enhance collapse_vars (#1862)
- extend expression types
  - `a++`
  - `a=x;`
- extend scan range
  - `for(init;;);`
  - `switch(expr){case expr:}`
  - `a = x; a = a || y;`
- terminate upon `debugger;`

closes #1821
fixes #27
fixes #315
fixes #1858
2017-05-06 16:15:43 +08:00
Alex Lam S.L
5a25d24b56 rename variables for better readability (#1863) 2017-05-02 20:47:10 +08:00
Alex Lam S.L
bffdc8dca8 update test/benchmark.js resources (#1864) 2017-05-02 19:48:12 +08:00
Alex Lam S.L
69b5663653 restore report of supported options (#1861)
fixes #1859
2017-05-02 01:42:29 +08:00
kzc
ea9289771b improve literal return optimization (#1860) 2017-05-02 00:10:11 +08:00
Alex Lam S.L
2cb55b2ad0 enforce toplevel on other compress options (#1855)
Respect "funcs" and "vars" properly.

fixes #1850
2017-04-30 22:52:36 +08:00
kzc
73d6438773 fix \\n and \\r in template strings (#1857)
fixes #1856
2017-04-30 17:05:32 +08:00
kzc
5c6316a37d fix class method formatting (#1853)
fixes #1852
2017-04-29 18:13:25 +08:00
kzc
bbb5f2a89c Update ISSUE_TEMPLATE.md (#1846) 2017-04-26 01:30:43 +08:00
Alex Lam S.L
76d19b60ad fix fuzzer on this (#1842)
- forbid redeclaration of `this`
- suppress probability for `this` within nested functions
2017-04-24 03:15:03 +08:00
Alex Lam S.L
9e62628171 fix unused on for-in statements (#1843)
Only need to avoid `var` within the initialisation block.

fixes #1841
2017-04-24 03:14:01 +08:00
Alex Lam S.L
9bf72cf758 improve parser under "use strict" (#1836)
- `const` without value
- `delete` of expression
- redefining `arguments` or `eval`

extend `test/ufuzz.js`
- optionally generate "use strict"
- improve handling of test cases with syntax errors
- group IIFE generation
- generate bare anonymous functions
- workaround `console.log()` for `new function()`
- generate expressions with `this`


fixes #1810
2017-04-23 20:05:22 +08:00
kzc
64d74432f6 update README for 3.x (#1840) 2017-04-23 04:28:32 +08:00
Alex Lam S.L
45ce369480 fix AST_For.init patch-up in drop_unused() (#1839)
fixes #1838
2017-04-23 01:51:56 +08:00
Alex Lam S.L
ca32a09032 fix label-related bugs (#1835)
- deep cloning of `AST_LabeledStatement`
- `L:do{...}while(false)`
- empty statement with label within block

extend `test/ufuzz.js`
- generate labels for blocks & loops
- generate for-in statements
- skip suspicious option search if `minify()` errs


fixes #1833
2017-04-22 22:15:04 +08:00
Roman Dvornov
6f954aa3d0 Fix API reference examples (#1834) 2017-04-21 02:23:41 +08:00
Alex Lam S.L
f05d4f7af3 improve unused (#1832)
- extract leading value with side-effects out of `var` statement
- reduce scanning of `AST_Definitions` from 3 passes to just once
2017-04-20 13:06:14 +08:00
Alex Lam S.L
88e7a542cd fix unused on labeled for-loop (#1831)
fixes #1830
2017-04-20 04:18:38 +08:00
Alex Lam S.L
4dcff038cb improve collapse_vars on AST_Var (#1828)
Perform the same cascaded scanning within `var` statement as we do on array of statements.
2017-04-19 04:49:09 +08:00
Alex Lam S.L
b4b9305db0 fix parser bugs & CLI reporting (#1827)
fixes #1825
2017-04-19 04:27:13 +08:00
Alex Lam S.L
28cfb65c47 extend cascade into a.b (#1829)
fixes #27
2017-04-19 04:17:15 +08:00
Alex Lam S.L
0f4f01b66c clean up collapse_vars (#1826)
- remove overlap in functionality of singular, consecutive reference of constant value
- remove workarounds for previous bugs in `lib/scope.js`
- distribute recursive `collapse_single_use_vars()` calls to their respective `OPT(AST_Node)`
- enable collapsing of variables within a single `AST_Definitions`
2017-04-18 21:45:34 +08:00
Alex Lam S.L
5d9f1da3ab support safe reassignments in reduce_vars (#1823)
`var a=1;a=2;x(a)` => `x(2)`

fix pre-existing issues
- reference counting on assignment
- walking of anonymous functions
- chained assignment
2017-04-18 13:38:42 +08:00
Alex Lam S.L
d1aa09c5c7 fix reduce_vars on conditionals (#1822) 2017-04-18 01:44:23 +08:00
Alex Lam S.L
6d5f341999 fix reduce_vars on boolean binary expressions (#1819)
Side effects of `&&` and `||` have not mattered until #1814, which takes assignment expressions into account.
2017-04-17 17:24:29 +08:00
Alex Lam S.L
4ffb6fce76 compress duplicated variable definitions (#1817)
These are surprisingly common, as people reuse the same variable name within loops or switch branches.
2017-04-17 17:11:29 +08:00
Alex Lam S.L
71a8d0d236 fix reduce_vars within try-block (#1818)
Possible partial execution due to exceptions.
2017-04-17 14:03:29 +08:00
Alex Lam S.L
1a498db2d3 enhance reduce_vars (#1814)
- allow immediate assignment after declaration of variable
- relax modification rule for immutable value
- fix order of visit for TreeWalker
- remove extraneous code
2017-04-17 01:36:50 +08:00
Alex Lam S.L
44dfa5a318 fix variable substitution (#1816)
- let `collapse_vars` take care of value containing any symbols
- improve overhead accounting
2017-04-16 17:25:39 +08:00
Alex Lam S.L
251ff1d1af update README (#1813)
- mention major version bump
- remove reference to internal API
2017-04-16 04:04:28 +08:00
Alex Lam S.L
ec443e422c unify CLI & API under minify() (#1811)
- rename `screw_ie8` to `ie8`
- rename `mangle.except` to `mangle.reserved`
- rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` 
- compact `sourceMap` options
- more stringent verification on input `options`
- toplevel shorthands
  - `ie8`
  - `keep_fnames`
  - `toplevel`
  - `warnings`
- support arrays and unquoted string values on CLI
- drop `fromString` from `minify()`
  - `minify()` no longer handles any `fs` operations
- unify order of operations for `mangle_properties()` on CLI & API
  - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor`
  - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()`
  - both will now do `Compressor`, `mangle_names()` then `mangle_properties()`
- `options.parse` / `--parse` for parser options beyond `bare_returns`
- add `mangle.properties.builtins` to disable built-in reserved list
  - disable with `--mangle-props builtins` on CLI
- `warnings` now off by default
- add `--warn` and `--verbose` on CLI
- drop `--enclose`
- drop `--export-all`
- drop `--reserved-file`
  - use `--mangle reserved` instead
- drop `--reserve-domprops`
  - enabled by default, disable with `--mangle-props domprops`
- drop `--prefix`
  - use `--source-map base` instead
- drop `--lint`
- remove `bin/extract-props.js`
- limit exposure of internal APIs
- update documentations

closes #96
closes #102
closes #136
closes #166
closes #243
closes #254
closes #261
closes #311
closes #700
closes #748
closes #912
closes #1072
closes #1366
fixes #101
fixes #123
fixes #124
fixes #263
fixes #379
fixes #419
fixes #423
fixes #461
fixes #465
fixes #576
fixes #737
fixes #772
fixes #958
fixes #1036
fixes #1142
fixes #1175
fixes #1220
fixes #1223
fixes #1280
fixes #1359
fixes #1368
2017-04-15 23:50:50 +08:00
Alex Lam S.L
32deb365d5 drop angular (#1812)
Remove support for `@ngInject` as there are proper alternatives anyway.
2017-04-15 05:52:29 +08:00
Alex Lam S.L
2244743545 convert AST_Seq from binary tree to array (#1460)
- rename `AST_Seq` to `AST_Sequence`
- raise default sequences_limit from 200 to 800
2017-04-12 21:56:27 +08:00
Alex Lam S.L
278577f3cb Merge pull request #1805 from alexlamsl/harmony-v2.8.22
Merging from master for 2.8.22
2017-04-09 17:27:30 +08:00
alexlamsl
0d8597e904 Merge branch 'master' into harmony-v2.8.22 2017-04-09 15:50:38 +08:00
Alex Lam S.L
04b8964505 v2.8.22 2017-04-09 11:36:57 +08:00
Alex Lam S.L
d6fbc365e2 fix LHS cases for NaN & friends (#1804)
`Infinity = beyond` should not become `1/0 = beyond`
2017-04-09 03:18:14 +08:00
Alex Lam S.L
9a978843f5 enhance test/ufuzz.js (#1803)
- `-E` to report test cases with runtime errors
- favor returning expressions rather than empty return
- emit a newline upon fuzzer completion to not erase the iteration count

closes #1800
2017-04-09 01:36:38 +08:00
Alex Lam S.L
0479ff0c54 fix a couple of bugs in global_defs (#1802)
- `optimize()` substituted expression
- compute nested property string correctly

fixes #1801

Miscellaneous
- reset optimisation flags on all node types
2017-04-08 16:46:25 +08:00
Alex Lam S.L
cf72fe552f fix delete corner cases (#1799)
- assignment
- boolean
- conditional
- sequence
2017-04-08 14:25:28 +08:00
Alex Lam S.L
a1532eb076 extend ufuzz generator (#1783)
- property access
- property assignment
- allow bare expression within try-block
- normalise `Error` in `console.log()`
- generate more unary expressions
- add parenthesis to enforce precedence
- adjust variable reuse/creation
- add parameters to function declaration & expression
- add return expression
- add trivial arguments to function call
2017-04-07 18:47:30 +08:00
Alex Lam S.L
c2a1bceb77 fix pure_getters for chained property access (#1798) 2017-04-07 17:06:01 +08:00
Alex Lam S.L
e3c9c22c75 fix corner cases with delete (#1796)
`delete Infinity` returns `false` where as `delete (1/0)` returns `true`
2017-04-07 15:39:59 +08:00
Alex Lam S.L
0f4cd73dcc introduce "strict" to pure_getters (#1795) 2017-04-07 13:31:58 +08:00
Alex Lam S.L
281e882d27 fix reduce_vars on catch variable (#1794)
Improved catch handling in `figure_out_scope()` means special case treatment of IE8 is no longer valid in `reset_opt_flags()`.

Also fixed recursive assignment in variable definition.
2017-04-07 12:32:56 +08:00
Alex Lam S.L
cc6aa3e5ac fix incorrect context in variable substitution (#1791)
`AST_Node.optimize()` is context-aware, so don't cache its results to be used elsewhere.

Also fixed a few cases of AST corruption and beef up safety of `pure_getters`.
2017-04-07 03:42:17 +08:00
Alex Lam S.L
e869779a98 enable inline_script by default (#1793) 2017-04-07 00:45:51 +08:00
Alex Lam S.L
06cdb74279 improve pure_getters (#1786)
- property access to `null` & `undefined` always has side effects
- utilise `reduce_vars` to determine safe property access
- may-be cases treated as side effects unless `unsafe`
2017-04-06 11:18:59 +08:00
Alex Lam S.L
ff289b90a9 implement delayed resolution for reduce_vars (#1788)
Although it would be nice to enforce `AST_Node` cloning during transformation, that ship has sailed a long time ago.

We now get the assigned value when resolving `AST_SymbolRef` instead of `reset_opt_flags()`, which has the added advantage of improved compressor efficiency.

fixes #1787
2017-04-05 21:06:42 +08:00
Alex Lam S.L
9b6bc67c33 optimise do{...}while(false) (#1785)
- better heuristics to avoid issues like #1532
- fix `TreeWalker.loopcontrol_target()`
  - `continue` cannot refer to `switch` blocks
2017-04-04 23:48:22 +08:00
Alex Lam S.L
4b90dc1fdb remove --mangle-props from fuzzing (#1777)
The inherently unsafe nature makes this feature unsuitable to be tested this way.

fixes #1774
2017-04-04 16:24:16 +08:00
Anthony Van de Gejuchte
c20bb99a62 Put expression after extend between parentheses if necessary (#1780) 2017-04-04 12:38:13 +08:00
Alex Lam S.L
951770fc68 exclude mangling of special property names (#1779)
- `null`
- `true`
- `false`
- numeric literals
2017-04-04 03:50:19 +08:00
Anthony Van de Gejuchte
2377171200 Fix walker not able to handle destr pattern in spread when compressing (#1438) 2017-04-04 01:23:22 +08:00
Anthony Van de Gejuchte
603d92effc Allow AST_DefaultAssign as parameter (#1778)
This may be the case for parsing arrow functions,
as left side expressions are converted to destructuring patterns
before being converted to parameters.
2017-04-04 00:46:05 +08:00
Alex Lam S.L
48b3fe9952 fix mangleProperties on identifiers (#1776)
- fix handling of "-Infinity"
- add test case for "-0"

reverts #1481
2017-04-03 23:17:47 +08:00
Alex Lam S.L
a400741868 workaround Node.js bugs (#1775)
Wrap test code in IIFE before passing to `vm`

fixes #1768
fixes #1771
2017-04-03 18:56:11 +08:00
Anthony Van de Gejuchte
17f0cc359f Allow empty destructuring (#1773) 2017-04-03 17:21:27 +08:00
Alex Lam S.L
59a4e56bc8 fix mangleProperties of undefined & Infinity (#1772)
`NaN` already works by the happy accident of `Number.NaN`

fixes #1770
2017-04-03 12:31:05 +08:00
Alex Lam S.L
1f1fccc45d extend test/ufuzz.js (#1769)
New expressions:
- property access
- array literal
- object literal

Miscellaneous:
- reduce execution timeout
- test `toplevel` and `mangleProperties`
2017-04-03 04:00:33 +08:00
Alex Lam S.L
35bae3fcd0 Merge pull request #1766 from alexlamsl/harmony-v2.8.21
Merging from master for 2.8.21
2017-04-02 18:10:58 +08:00
alexlamsl
4614b5b46e Merge branch 'master' into harmony-v2.8.21 2017-04-02 17:25:20 +08:00
Alex Lam S.L
b7f6b73f4e v2.8.21 2017-04-02 17:07:55 +08:00
Alex Lam S.L
9469c03ac9 fix corner case in switch (#1765) 2017-04-02 17:07:20 +08:00
Alex Lam S.L
d57527697f avoid confusion of NaN & Infinity with catch symbol of the same name (#1763)
fixes #1760
fixes #1761
2017-04-02 16:14:09 +08:00
Alex Lam S.L
f7ca4f2297 fix corner cases in switch and undefined (#1762)
- fix side effects in switch condition for singular blocks
- fix `undefined` confusion with local variable
- gate `OPT(AST_Switch)` with `switches`

fixes #1758
fixes #1759
2017-04-02 14:52:25 +08:00
Alex Lam S.L
c076e7b60d speed up fuzzer code generation (#1757)
- only output one top-level function or statement block
- reduce `rng()` granularity from 2^32 to 65536
- fix overflow in `rng()`
- track `canThrow` during `typeof` creation
2017-04-02 05:11:29 +08:00
Alex Lam S.L
4a55bb0be5 minor tweaks to test/ufuzz.js (#1756)
- count iterations from `1` instead of `0`
- remove `unsafe` from default set of `minify()` tests
- improve usability of help
2017-04-02 03:17:01 +08:00
Alex Lam S.L
28ecea50a6 upgrade fuzzer (#1754)
- configurable set of `minify()` options
- test and report suspects upon failure
- continue after failure if infinite iterations is specified
2017-04-02 02:10:50 +08:00
kzc
9a311705f5 fuzz regexp literals, more constant numbers, typeof expression (#1755) 2017-04-02 02:08:46 +08:00
Alex Lam S.L
ee3fe0f4cd fix switch branch elimination (#1752)
Merge unreachable case body with previous fallthrough case

fixes #1750
2017-04-01 17:19:57 +08:00
Alex Lam S.L
87f6e1b091 minor tweaks to fuzzer (#1751)
- remove `let` as variable name
- employ `crypto.randomBytes()`
2017-04-01 17:09:52 +08:00
Alex Lam S.L
c934fc8142 implement test/sandbox.js (#1749)
- `test/run-tests.js` and `test/ufuzz.js` now shares the same `run_code()` and `same_stdout()`
- re-enable fuzzer to generate top-level `NaN`, `Infinity` & `undefined`
- attempt to show beautified output only when `run_code()` output is preserved
2017-04-01 05:47:11 +08:00
Alex Lam S.L
257ddc3bdb improve compression of undefined, NaN & Infinitiy (#1748)
- migrate transformation logic from `OutputStream` to `Compressor`
- always turn `undefined` into `void 0` (unless `unsafe`)
- always keep `NaN` except when avoiding local variable redefinition
- introduce `keep_infinity` to suppress `1/0` transform, except when avoiding local variable redefinition

supersedes #1723
fixes #1730
2017-04-01 03:02:14 +08:00
Alex Lam S.L
1ddc05725d combine rules for binary boolean operations (#1744) 2017-03-31 18:47:44 +08:00
Ondřej Španěl
2f93058c6e More variants of import added (#1738)
- `import * from "x.js"`
- `import * as Name from "x.js"`
2017-03-31 17:52:56 +08:00
Ondřej Španěl
a729c43e87 Another variant of export added - export {Name}. (#1737) 2017-03-31 17:51:27 +08:00
Peter van der Zee
e6b76a4879 Massive extension of the fuzzer (#1697)
Fix bug where a `throw` was generated without expression

Reenable try/catch/finally and fix them up

Skip serialization errors

Allow function decl in other funcs but not in blocks etc

Rename function to be more appropriate

Fix global functions not getting certain names

Make the canaries more likely to appear as expressions

Add a silly rounding edge case

Add a new canary, `c`, which should only ever be incremented

Refactoring

Fix (another) iife not actually being invoked

When a statement hits recursion max return an expression instead of `;`

When a expression hits recursion max also inc `c`

Generate global code as well as function code

Also fixes some argument juggling related bugs.
No longer reduces the recursion max when generating sub functions.
Generates a function arg.

Add used names to var name pool while in that scope

This is a little wonky, possibly a hack, but since it's synchronous code I think it's alright to do this. The alternative is to slice the varnames array and juggle them through almost all the generator functions and there are various reasons why this patch is a better alternative.

Minify generated code, not beautified code. Prevents beautifier bias.

Prevent unnecessary duplication

Remove serialization protection because I think it got handled elsewhere

Abstract toplevel code generation

Add example line of running test case

Add poor man options parser, and some options

Reindent to 4 spaces

Lower chance of `default` generation

Comment example of testing a case and output improvement

Enable `default` clause appearing at any clause index

Removing some training wheels; dont add parens where we dont absolutely need them

Support `-s1` and `-s2` to force specific statements being generated at that recursion level

Add round number to output when failing. For stats and fun and profit.

Solidify statement depth counting. The argument juggling is real.

Renamed option to something long. -scf was ugly and probably confusing.

Fix missing arguments causing `canThrow` to be truthy, generating crashing code

Generate more binary nested expressions

Add black and white list cli options for statement generation

Allows you to explicitly require or forbid certain statements from/to being made.

```
node test/ufuzz.js --without-stmt switch,try -t 5 -r 5 -V
```

```
node test/ufuzz.js --only-stmt ifelse,expr -t 5 -r 5 -V
```

Similar granularity for expression may be added later.

There can be no comma between names; it just does a split on that arg.

Trim down the binary expression generator

Prevent scoping issues in nodejs by preventing certain names in global space

Oh this list was incomplete?

Allow bin-expr to generate assignments too. More vigilant with storing and reusing vars.

Add more global builtin names

Update wrapper code

Also patch Function valueOf
2017-03-31 17:23:50 +08:00
Alex Lam S.L
a0c3836ba0 sort options in alphabetical order (#1743)
They started off as functional groups I guess, but given the sheer number of options this is becoming too difficult to read.
2017-03-31 16:41:04 +08:00
Alex Lam S.L
f8a71b56fd v2.8.20 2017-03-31 15:27:40 +08:00
Alex Lam S.L
11e9bdc427 fix missing preamble when shebang is absent (#1742) 2017-03-31 15:26:57 +08:00
Alex Lam S.L
66e9039350 Merge pull request #1740 from alexlamsl/harmony-v2.8.19
Merging from master for 2.8.19
2017-03-31 13:28:56 +08:00
alexlamsl
d717bf9ce8 Merge branch 'master' into harmony 2017-03-31 12:54:03 +08:00
Alex Lam S.L
a84564d1a8 v2.8.19 2017-03-31 12:26:10 +08:00
Alex Lam S.L
c595b84032 fix catch symbol mangling (#1734)
Only need to look up the immediate non-block/catch scope for the same-name special case.

fixes #1733
2017-03-31 02:57:47 +08:00
Ondřej Španěl
5dea52266b [ES6] Implemented parse for export Name from Module variants. (#1701)
- add `AST_Export` new variants output
- add tests to `test/compress/`
- update `$propdoc` of `AST_Export` ("exported_names" & "module_name")
- add tests for `export ...  as ...` variants
2017-03-30 17:07:50 +08:00
Alex Lam S.L
7cb1adf455 remove paranthesis for -(x*y) (#1732) 2017-03-30 16:09:00 +08:00
Alex Lam S.L
7bea38a05d optimize try-catch-finally (#1731)
- eliminate empty blocks
- flatten out if try-block does not throw
2017-03-30 12:16:58 +08:00
Alex Lam S.L
0f910ee25c improve tests from #1726 (#1729) 2017-03-30 00:13:46 +08:00
Alex Lam S.L
beb9659778 speed up IIFE elimination (#1728)
- `side_effects` will clean up inner statements, so checking for an empty function body should suffice
- drop side effects when dropping `return` from statement
2017-03-29 23:27:35 +08:00
Alex Lam S.L
f1a833a7aa speed up equivalent_to() and AST_Switch (#1727) 2017-03-29 22:08:26 +08:00
Alex Lam S.L
2e41cd6394 fix missing parentheses around NaN/Infinity shorthands (#1726)
fixes #1724
fixes #1725
2017-03-29 20:53:03 +08:00
Alex Lam S.L
09f77c7d4d output optimal representations of NaN & Infinity (#1723)
- move these optimisations out from `Compressor` to `OutputStream`
- fixes behaviour inconsistency when running uglified code from global or module levels due to redefinition
2017-03-29 18:31:55 +08:00
Alex Lam S.L
fef0bf9ee0 improve beautified output of switch blocks (#1721) 2017-03-29 04:40:05 +08:00
Alex Lam S.L
ae740b933f v2.8.18 2017-03-29 03:13:30 +08:00
Alex Lam S.L
ec7f37f314 remove UGLIFY_DEBUG (#1720)
fixes #1719
2017-03-29 01:27:24 +08:00
Alex Lam S.L
fccefbeaca Merge pull request #1717 from alexlamsl/harmony-v2.8.17
Merging from master for 2.8.17
2017-03-29 01:01:28 +08:00
Alex Lam S.L
eb48a035e7 fix corner case in unused (#1718)
When fixing catch-related issue in #1715, it tries to optimise for duplicate definitions but did not take anonymous functions into account.

Remove such optimisation for now and we can cover this as a more general rule later.
2017-03-29 01:00:21 +08:00
alexlamsl
1e2b0aaa04 Merge branch 'master' into harmony-v2.8.17 2017-03-28 22:03:46 +08:00
Alex Lam S.L
6ab3224c0d v2.8.17 2017-03-28 21:49:04 +08:00
Alex Lam S.L
c909ffb715 fix unused on var of the same name within catch (#1716)
fixes #1715
2017-03-28 21:25:49 +08:00
Alex Lam S.L
f71f4905b0 fix is_number() on += (#1714)
fixes #1710
2017-03-28 17:08:16 +08:00
Alex Lam S.L
fb177a6312 drop anonymous function name when overshadowed by other declarations (#1712)
fixes #1709
2017-03-28 17:02:20 +08:00
Alex Lam S.L
65da9acce6 handle var within catch of the same name (#1711)
The following code prints `1`:

var a = 1;
!function(){
  a = 4;
  try{
    throw 2;
  } catch (a) {
    var a = 3;
  }
}();
console.log(a);

fixes #1708
2017-03-28 16:42:39 +08:00
Alex Lam S.L
67d0237f73 fix tail trimming of switch blocks (#1707)
now guarded under `dead_code`

fixes #1705
2017-03-28 03:59:13 +08:00
Alex Lam S.L
984a21704e fix mangle for variable declared within catch block (#1706)
fixes #1704
2017-03-28 03:26:35 +08:00
Alex Lam S.L
aa3f647656 ufuzz: workaround for Function.toString() v2 (#1700) 2017-03-27 21:49:08 +08:00
Alex Lam S.L
c526da59a1 has_side_effects() should take AST_Switch.expression into account (#1699)
fixes #1698
2017-03-27 18:09:35 +08:00
Alex Lam S.L
581630e0a7 fix typeof side effects (#1696)
`statement_to_expression()` drops `typeof` even if it operates on undeclared variables.

Since we now have `drop_side_effect_free()`, replace and remove this deprecated functionality.
2017-03-27 04:37:42 +08:00
Alex Lam S.L
f5952933a0 preserve side effects in switch expression (#1694)
fixes #1690
2017-03-27 02:32:46 +08:00
Alex Lam S.L
f001e4cb9d fix cascade on anonymous function reference (#1693)
Unlike normal variables and even function definitions, these cannot be reassigned, even though assignment expressions would "leak" the assigned value as normal.
2017-03-27 01:58:21 +08:00
Alex Lam S.L
57ce5bd9e0 handle overlapped variable definitions (#1691)
Process variable definitions with or without assigned values against:
- `arguments`
- named function arguments
- multiple definitions within same scope

Essentially demote variable declarations with no value assignments.

Also fixed invalid use of `AST_VarDef` over `arguments` - should use a member of `AST_SymbolDeclaration` instead.
2017-03-27 01:30:21 +08:00
Alex Lam S.L
861a79ac9f fix delete related issues in collapse_vars and reduce_vars (#1689) 2017-03-26 19:14:30 +08:00
Alex Lam S.L
00996afd2c ufuzz: workaround function name and toString() (#1688)
fixes #1686
2017-03-26 18:18:44 +08:00
Alex Lam S.L
e76fb354eb fix cascade on delete operator (#1687)
Conditions including strict mode would make `delete` return `true` or `false`, and are too complex to be evaluated by the compressor.

Suppress assignment folding into said operator.

fixes #1685
2017-03-26 18:08:44 +08:00
Alex Lam S.L
3276740779 fallthrough should not execute case expression (#1683)
- de-duplicate trailing cases only, avoid all potential side-effects
- enable switch statement fuzzing

fixes #1680
2017-03-26 16:52:38 +08:00
kzc
5509e51098 optimize conditional when condition symbol matches consequent (#1684) 2017-03-26 16:36:33 +08:00
Alex Lam S.L
94f84727ce suppress switch branch de-duplication upon side effects (#1682)
fixes #1679
2017-03-26 13:32:43 +08:00
Alex Lam S.L
8a4f86528f fix side-effects detection on switch statements (#1678)
extension of #1675
2017-03-26 12:05:44 +08:00
Peter van der Zee
adb0e882e9 Improve fuzzer. :) (#1665)
@qfox	Put value constants in a global constant			74c0fb9
 @qfox	And the other string based values as well			a5033c5
 @qfox	Be more strict about parameters, allow max to be optional			9c7ce70
 @qfox	Support a `V` (capital) flag to only log out at intervals			2d822c7
 @qfox	Fewer magic variables			a6a9a7c
 @qfox	Fix decrement such that a function is created when n=1			7e4b017
 @qfox	Add more values			64e596e
 @qfox	Make `b` appear more often			d33191a
 @qfox	Add functions that contain (only..) functions			29a86e3
 @qfox	Allow the block statement to contain multiple statements			7570484
 @qfox	Make the interval count a constant			d587ad8
 @qfox	Enable mangling, disable post-processing  …			4dc8d35
 @qfox	Add more simple value that may trigger syntactic errors			8496d58
 @qfox	Add `else` to some `if` statements			a4aed65
 @qfox	Move iife to expr generator, fix missing recursion arg			e453159
 @qfox	Improve output on error where it wasnt printing the last code properly			4565a1a
 @qfox	Add switch statement to generator			ceafa76
 @qfox	Add var statement, support optional comma for expr generator			b83921b
 @qfox	Expression generator should use a simple value instead of `0` as recu…  …			9d1a5c7
 @qfox	const -> var to keep things es5...			0143099
 @qfox	Add more simple values that may trigger edge cases			5e124f1
 @qfox	Add central name generator, take special care for global functions			aeb7682
 @qfox	Add some `return` and function declaration cases to statement generator			6c9c3cc
 @qfox	Exclude switches from generator for now			91124b2

Put value constants in a global constant

And the other string based values as well

Be more strict about parameters, allow max to be optional

Support a `V` (capital) flag to only log out at intervals

Fewer magic variables

Fix decrement such that a function is created when n=1

Add more values

Make `b` appear more often

Add functions that contain (only..) functions

Allow the block statement to contain multiple statements

Make the interval count a constant

Enable mangling, disable post-processing

Mangling is kind of the whole point...

Similarly, to beautify the minified code afterwards may supress bugs so it's probably best not to beautify the code prematurely. And there's no point anyways since you won't see it most of the time and only care about the main input anyways.

Add more simple value that may trigger syntactic errors

Add `else` to some `if` statements

Move iife to expr generator, fix missing recursion arg

Improve output on error where it wasnt printing the last code properly

Add switch statement to generator

Add var statement, support optional comma for expr generator

Expression generator should use a simple value instead of `0` as recursion default

const -> var to keep things es5...

Add more simple values that may trigger edge cases

Add central name generator, take special care for global functions

Add some `return` and function declaration cases to statement generator

Exclude switches from generator for now

Enable switch generation because #1667 was merged

Add typeof generator

Add some elision tests

Add a new edge case that returns an object explicitly

Add all binary ops to try and cover more paths

Forgot four binops and added `Math` to var name pool

Harden the incremental pre/postfix tests

Improve switch generator, allow `default` to appear at any clause index

Add try/catch/finally generation

Prevent function statements being generated

Add edge case with decremental op and a group

Disable switch generation until #1679 and #1680 are solved

Only allow `default` clause as last clause for now

Tentatively enable `throw`, `break` and `continue` statements when in valid contexts
2017-03-26 12:04:50 +08:00
kzc
6a54de79b5 optimize trivial arrow functions with a return statement in braces (#1681)
fixes #1676
2017-03-26 12:03:11 +08:00
Alex Lam S.L
f83d370f57 improve switch optimisations (#1677)
- correctly determine reachability of (default) branches
- gracefully handle multiple default branches
- optimise branches with duplicate bodies

fixes #376
fixes #441
fixes #1674
2017-03-26 05:15:46 +08:00
Alex Lam S.L
b19aa58cff fix has_side_effects() (#1675)
`AST_Try` is an `AST_Block`, so besides try block we also need to inspect catch and finally blocks for possible side effects.

Also extend this functionality to handle `AST_If` and `AST_LabeledStatement` while we are at it.

fixes #1673
2017-03-25 23:03:26 +08:00
Alex Lam S.L
0a65de89b9 fix reduce_vars on AST_Switch (#1671)
Take conditional nature of switch branches into account.

fixes #1670
2017-03-25 21:17:30 +08:00
Alex Lam S.L
6e86ee950d fix typeof side-effects (#1669)
`has_side_effects()` does not take `typeof`'s magical power of not tripping over undeclared variable into account.

fixes #1668
2017-03-25 17:40:18 +08:00
Alex Lam S.L
8ca2401ebe fix dead_code on AST_Switch (#1667)
Need to call `extract_declarations_from_unreachable_code()`.

fixes #1663
2017-03-25 16:21:42 +08:00
Alex Lam S.L
491f16c766 v2.8.16 2017-03-25 03:21:16 +08:00
Alex Lam S.L
a30092e20f fix invalid AST_For.init (#1657)
Turns out the only place in `Compressor` which can generate invalid `AST_For.init` is within `drop_unused()`, so focus the fix-up efforts.

supercedes #1652
fixes #1656
2017-03-25 03:18:36 +08:00
Alex Lam S.L
b1abe92e1a introduce ufuzz.js (#1655)
closes #1647
2017-03-25 01:46:12 +08:00
Alex Lam S.L
b454ce667e Update ISSUE_TEMPLATE.md 2017-03-24 23:12:58 +08:00
Alex Lam S.L
32283a0def fix cascade of evaluate optimisation (#1654)
Operator has changed, so break out from rest of the rules.

fixes #1649
2017-03-24 22:09:19 +08:00
Alex Lam S.L
ac51d4c5a0 fix corner case in AST_For.init (#1652)
Enforce `null` as value for empty initialisation blocks.

fixes #1648
2017-03-24 19:31:17 +08:00
Alex Lam S.L
0432a7abb9 fix assignment extraction from conditional (#1651)
fixes #1645
fixes #1646
2017-03-24 18:52:48 +08:00
Alex Lam S.L
f3a1694a41 fix assignment substitution in sequences (#1643)
take side effects of binary boolean operations into account

fixes #1639
2017-03-24 14:30:31 +08:00
Alex Lam S.L
2e0dc97003 improve error marker placement (#1644)
For AST_UnaryPrefix, points to the operator rather than end of expression.
2017-03-24 14:28:40 +08:00
Alex Lam S.L
701035621d fix expect_stdout (#1642)
`compress()` may modify input ASTs

add tests for #1627 & #1640
2017-03-24 13:19:50 +08:00
kzc
79334dda10 fix regression: CLI options with hyphens like -b ascii-only (#1640)
fixes #1637
2017-03-24 11:55:03 +08:00
Alex Lam S.L
e918748d88 improve collapsible value detection (#1638)
- #1634 bars variables with cross-scope references in between to collapse
- but if assigned value is side-effect-free, no states can be modified, so it is safe to move
2017-03-24 02:55:32 +08:00
Alex Lam S.L
9e2290b29c Merge pull request #1636 from alexlamsl/harmony-v2.8.15
Merging from master for 2.8.15
2017-03-23 16:08:53 +08:00
alexlamsl
97d0fc271d Merge branch 'master' into harmony-v2.8.15 2017-03-23 15:28:17 +08:00
Alex Lam S.L
6b2f34769a v2.8.15 2017-03-23 13:36:47 +08:00
Alex Lam S.L
48ffbef51d account for cross-scope modifications in collapse_vars (#1634)
mostly done by @kzc

fixes #1631
2017-03-23 07:17:34 +08:00
Alex Lam S.L
c0f3feae9f introduce compressor.info() (#1633)
report the following only when `options.warnings = "verbose"`
- unused elements due to inlining
- collpased variables
2017-03-23 06:49:49 +08:00
Alex Lam S.L
a00040dd93 fix a bug in simple_glob (#1632)
- "?" should not match "/"
- other minor clean-ups
2017-03-23 06:11:16 +08:00
Alex Lam S.L
ee95c1b38b metadata cleanup (#1630)
- mention performance anomaly in Node 7 and drop from CI
- remove unused npm "scripts"
- mark browserify dependency as optional
- stop `test/mozilla-ast.js` from spamming console output in later versions of Node.js
2017-03-23 01:31:46 +08:00
Alex Lam S.L
4bceb85cbf throw parse error on invalid assignments (#1627)
fixes #1626
2017-03-21 14:11:32 +08:00
Alex Lam S.L
7906033e82 Merge pull request #1624 from alexlamsl/harmony-v2.8.14
Merging from master for 2.8.14
2017-03-19 18:24:29 +08:00
alexlamsl
4bf21ce5c1 add expect_stdout to tests 2017-03-19 15:35:39 +08:00
alexlamsl
44d6b47bdc Merge branch 'master' into harmony-v2.8.14 2017-03-19 15:31:18 +08:00
Alex Lam S.L
30a75049f5 v2.8.14 2017-03-19 15:24:57 +08:00
Alex Lam S.L
a3cc3a9b87 make expect_stdout work on Node.js 0.12 (#1623)
That particular version of Node.js has messed up error messages, so provide a version-specific workaround.

Also fixed an formatting issue which would cause `expect_stdout` to fail if error message contains excerpts of input.

Apply `expect_stdout` to more applicable tests.
2017-03-19 12:00:32 +08:00
Alex Lam S.L
96f8befdd7 fix commit 88fb83a (#1622)
The following is wrong:
    `a == (b ? a : c)` => `b`
Because:
- `b` may not be boolean
- `a` might have side effects
- `a == a` is not always `true` (think `NaN`)
- `a == c` is not always `false`
2017-03-19 11:59:42 +08:00
Alex Lam S.L
cd58635dcc fix AST_Binary.lift_sequences() (#1621)
Commit eab99a1c fails to account for side effects from compound assignments.
2017-03-19 03:04:22 +08:00
Alex Lam S.L
274331d0ea transform String.charAt() to index access (#1620)
Guarded by `unsafe` as `charAt()` can be overridden.
2017-03-19 02:17:15 +08:00
Alex Lam S.L
129e449c8e Merge pull request #1614 from alexlamsl/harmony-v2.8.13
Merging from master for 2.8.13
2017-03-18 13:02:09 +08:00
alexlamsl
75c3c8963f Merge branch 'master' into harmony-v2.8.13 2017-03-18 02:52:45 +08:00
Alex Lam S.L
0489d6de64 handle runtime errors in expect_stdout (#1618)
allow test to pass if both `input` and `expect` throws the same kind of error
2017-03-18 02:33:51 +08:00
Alex Lam S.L
fb092839c2 fix top-level directives in compress tests (#1615)
`input` and `expect` are parsed as `AST_BlockStatement` which does not support `AST_Directive` by default.

Emulate that by transforming preceding `AST_SimpleStatement`s of `AST_String` into `AST_Directive`.
2017-03-18 01:56:15 +08:00
Alex Zaworski
d26b7522d9 Allow 'name' as object literal shorthand property (#1617)
fixes #1613
2017-03-18 01:29:13 +08:00
Christian Maughan Tegnér
b7c112eefe Add --in-source-map inline documentation (#1611) 2017-03-17 03:08:38 +08:00
Alex Lam S.L
b2b8a0d386 v2.8.13 2017-03-17 02:01:33 +08:00
Alex Lam S.L
ac40301813 fix chained evaluation (#1610)
`reduce_vars` enables substitution of variables but did not clone the value's `AST_Node`.

This confuses `collapse_vars` and result in invalid AST and subsequent crash.

fixes #1609
2017-03-17 00:26:48 +08:00
Alex Lam S.L
3563d8c09e extend test/run-tests.js to optionally execute uglified output (#1604)
fixes #1588
2017-03-16 23:20:06 +08:00
Alex Lam S.L
5ae04b3545 make collapse_vars consistent with toplevel (#1608)
fixes #1605
2017-03-16 13:22:26 +08:00
Alex Lam S.L
a80b228d8b fix hoist_vars on reduce_vars (#1607)
`hoist_vars` converts variable declarations into plain assignments, which then confuses `reduce_vars`

fixes #1606
2017-03-16 12:03:30 +08:00
Alex Lam S.L
cf4bf4ceb1 fix stack issues with AST_Node.evaluate() (#1603)
As patched in #1597, `make_node_from_constant()` makes inconsistent and sometimes incorrect calls to `optimize()` and `transform()`.

Fix those issues properly by changing the semantics of `evaluate()` and `make_node_from_constant()`, with the side effect that `evaluate()` no longer eagerly converts constant to `AST_Node`.
2017-03-16 01:02:59 +08:00
Alex Lam S.L
8223b2e0db fix AST_Node.optimize() (#1602)
Liberal use of `Compressor.transform()` and `AST_Node.optimize()` presents an issue for look-up operations like `TreeWalker.in_boolean_context()` and `TreeWalker.parent()`.

This is an incremental fix such that `AST_Node.optimize()` would now contain the correct stack information when called correctly.
2017-03-15 18:44:13 +08:00
Alex Lam S.L
2fd86d3cb0 Merge pull request #1601 from alexlamsl/harmony-v2.8.12
Merging from master for 2.8.12
2017-03-14 14:29:32 +08:00
Alex Lam S.L
381bd3836e minor clean-ups (#1600)
- remove obsolete optimisation in `AST_Binary` after #1477
- improve `TreeWalker.has_directive()` readability and resilience against multiple visits
2017-03-14 13:19:05 +08:00
alexlamsl
8f7ab602e2 Merge branch 'master' into harmony-v2.8.12 2017-03-14 13:17:42 +08:00
Alex Lam S.L
1dd339f95e fix unused crashes (#1599)
- `AST_DefaultAssign` on `keep_fargs`
- `AST_Expansion on` `keep_fargs`
- `AST_Destructuring` on top-level declarations without `toplevel`
2017-03-14 13:13:43 +08:00
Alex Lam S.L
919d5e3482 v2.8.12 2017-03-11 05:00:55 +08:00
Alex Lam S.L
e3a3db73ae temporary fix for boolean bug (#1597)
fixes #1592
2017-03-11 04:59:55 +08:00
Alex Lam S.L
d9344f30b8 disallow parameter substitution for named IIFEs (#1596)
Self-referenced function has non-fixed values assigned to its parameters.

Let `unused` & `!keep_fnames` do the scanning, then apply `reduce_vars` only to unnamed functions.

fixes #1595
2017-03-11 03:34:55 +08:00
Alex Lam S.L
c7063c1f38 Merge pull request #1591 from alexlamsl/harmony-v2.8.11
Merging from master for 2.8.11
2017-03-10 16:38:23 +08:00
Alex Lam S.L
be80f7e706 support multi-line string in tests (#1590)
`expect_exact` sometimes have multiple lines and `\n` are hard to read.

Use array of strings to emulate line breaks and improve readability.
2017-03-10 11:27:30 +08:00
alexlamsl
f4a12b34f2 Merge branch 'master' into harmony-v2.8.11 2017-03-10 11:17:49 +08:00
Alex Lam S.L
cf45e2f79b fixup for #1585 (#1589)
As patched on `harmony`, `statement()` is the only user of `embed_tokens()` with a missing error branch.

Updated test case and match up with `harmony` to facilitate future merging.
2017-03-10 10:49:41 +08:00
Alex Lam S.L
8354758f30 v2.8.11 2017-03-10 04:17:21 +08:00
Alex Lam S.L
9e6b128374 fix catch variable reference in IE8 (#1587)
`AST_Scope.def_variable()` will overwrite `AST_Symbol.thedef`, so save a copy before calling.

fixes #1586
2017-03-10 03:15:21 +08:00
Michael Mior
93cdb194f4 Correctly raise a parse exception with a missing loop body (#1585) 2017-03-10 03:08:43 +08:00
Alex Lam S.L
b633706ce4 fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account
- if unused parameter cannot be eliminated, replace it with `0`

fixes #1583
2017-03-09 19:11:05 +08:00
Alex Lam S.L
5d5c7934a5 Merge pull request #1582 from alexlamsl/harmony-v2.8.10
Merging from master for 2.8.10
2017-03-09 13:14:55 +08:00
alexlamsl
8f4b45f4f8 Merge branch 'master' into harmony-v2.8.10 2017-03-09 06:02:28 +08:00
Alex Lam S.L
e9920f7ca1 v2.8.10 2017-03-09 05:48:06 +08:00
Alex Lam S.L
7e465d4a01 scan RHS of dropped assignments (#1581)
- similar case as #1578 but against #1450 instead
- fix `this` binding in #1450 as well

closes #1580
2017-03-09 05:22:27 +08:00
Alex Lam S.L
aa80ee349d remove checkboxes from Issues template 2017-03-08 19:19:54 +08:00
Alex Lam S.L
80e81765cf explain how to make a proper bug report (#1579)
fixes #1574
2017-03-08 18:56:01 +08:00
Alex Lam S.L
711f88dcb4 scan assignment value in drop_unused() (#1578)
those were not optimised for `unused` before, which made it necessary for `reduce_vars` to have separate steps for `keep_fnames`

docs update by @kzc

closes #1577
2017-03-08 18:37:32 +08:00
Alex Lam S.L
344d11d591 v2.8.9 2017-03-08 12:41:22 +08:00
Alex Lam S.L
c7cdcf06a6 fix function name eliminiation (#1576)
Function expression can be assigned to a variable and be given a name. Ensure function name is the reduced variable before clearing it out.

fixes #1573
fixes #1575
2017-03-08 12:39:57 +08:00
Alex Lam S.L
3ee55748d4 only run benchmark & jetstream on CI (#1571) 2017-03-08 06:00:51 +08:00
Alex Lam S.L
dedbeeff15 plan B for IE8 do-while semi-colon fix (#1572)
- omitting trailing semi-colon in do-while breaks non-browser parser, e.g. uglify-js 1.x
- trailing semi-colon only breaks IE8 if followed by `else` or `while`
- always use braces in do-while body to workaround 2nd case with no size loss in compression

fixes #1568
2017-03-08 05:07:05 +08:00
Alex Lam S.L
bd6dee52ab fix return from recursive IIFE (#1570)
`side-effects` did not account for IIFEs being able to reference itself thus making its return value potentially significant
2017-03-08 03:31:51 +08:00
Alex Lam S.L
952e2656eb Merge pull request #1567 from alexlamsl/harmony-v2.8.8
Merging from master for 2.8.8
2017-03-07 23:56:23 +08:00
qinayi
240383a314 is_block_scope return true when current node is an instance of AST_IterationStatement. then the scope of let variable can be figured out accurately (#1561) 2017-03-07 23:50:58 +08:00
alexlamsl
250b782b1e Merge branch 'master' into harmony-v2.8.8 2017-03-07 20:25:52 +08:00
Alex Lam S.L
144052ca49 v2.8.8 2017-03-07 19:58:41 +08:00
Alex Lam S.L
65c848cc6f include benchmark.js in test suite (#1564)
- report file sizes and overall run time
- exit with non-zero code upon error
2017-03-07 19:25:12 +08:00
Alex Lam S.L
8a8a94a596 fix deep cloning of labels (#1565)
`AST_Label.references` get `.initialize()` to `[]` every time after `.clone()`

So walk down the tree to pick up the cloned `AST_LoopControl` pieces and put it back together.
2017-03-07 18:38:27 +08:00
Alex Lam S.L
8153b7bd8a transform function calls to IIFEs (#1560)
- expose function body to call sites for potential optimisations
- suppress substitution of variable used within `AST_Defun`
2017-03-07 15:37:52 +08:00
Alex Lam S.L
d787d70127 avoid substitution of global variables (#1557)
- unless `toplevel` is enabled
- global `const` works as before
2017-03-07 03:11:03 +08:00
kzc
3ac2421932 collapse_vars: do not replace a constant in loop condition or init (#1562) 2017-03-07 01:42:33 +08:00
Alex Lam S.L
a9fc9ddc33 suppress semicolons after do/while (#1556)
- unless both `beautify` & `screw-ie8` are enabled
- deprecate workaround for if-do-while-else

fixes #186
2017-03-06 17:31:35 +08:00
Alex Lam S.L
3c2b3aeddb Merge pull request #1554 from alexlamsl/harmony-v2.8.6
Merging from master for 2.8.7
2017-03-05 23:03:30 +08:00
alexlamsl
aa605495f8 Merge branch 'master' into harmony-v2.8.6 2017-03-05 21:42:34 +08:00
kzc
33a26d456b patch up #1543 for harmony
fixes #1537
2017-03-05 21:39:31 +08:00
Alex Lam S.L
a5d62a3fc6 v2.8.7 2017-03-05 17:17:08 +08:00
Alex Lam S.L
067e5a5762 fixup for #1553 (#1555)
- `++a` is the one that is foldable
- transform `a++` into `++a` for better optimisation
2017-03-05 17:15:37 +08:00
alexlamsl
49d9ac1c43 Merge branch 'master' into harmony-v2.8.6 2017-03-05 16:03:56 +08:00
Alex Lam S.L
33b5f31984 v2.8.6 2017-03-05 15:48:28 +08:00
Alex Lam S.L
35a849dc48 collapse assignment with adjacent subsequent usage (#1553)
- consolidate `cascade` optimisations
- support ++/-- postfixes
- remove redundant optimisation identified in #1460

fixes #368
2017-03-05 14:56:14 +08:00
Alex Lam S.L
b70591be1a handle variable declaration within catch blocks (#1546)
accounts for IE8- scoping
2017-03-05 13:13:44 +08:00
Alex Lam S.L
b33e7f88e6 improve unsafe on undefined (#1548)
`unsafe` turns undefined keyword into a variable of the same name if found, but that interferes with other related optimisations.

Keep track of such transformations to ensure zero information loss in the process.
2017-03-05 13:09:27 +08:00
Alex Lam S.L
1f0333e9f1 stay safe with constants in IE8- (#1547)
- `undefined` etc. can be redefined at top-level for IE8-, so disable related optimisations
- fixed `--support-ie8` catch mangle bug
2017-03-05 12:51:11 +08:00
Alex Lam S.L
eb98a7f2f3 fix handling of shebang and preamble (#1545)
fixes #1332
2017-03-05 12:16:02 +08:00
Alex Lam S.L
78d1bb92d4 fix a corner case in #1530 (#1552) 2017-03-05 12:12:59 +08:00
Alex Lam S.L
ea9ab9fb0e resolve issue with outdated version of async (#1549)
fixes #746
2017-03-05 01:54:20 +08:00
kzc
ce54c9ccee disallow collapse_vars constant replacement in for-in statements (#1543) 2017-03-04 02:39:54 +08:00
Alex Lam S.L
07accd2fbb process code with implicit return statement (#1522)
Bookmarklet for instance implicitedly assumes a "completion value" without using `return`.
The `expression` option now supports such use cases.
Optimisations on IIFEs also enhanced.

fixes #354
fixes #543
fixes #625
fixes #628
fixes #640
closes #1293
2017-03-03 18:13:07 +08:00
Alex Lam S.L
18059cc94f compress numerical expressions (#1513)
safe operations
- `a === b` => `a == b`
- `a + -b`  => `a - b`
- `-a + b`  => `b - a`
- `a+ +b`   => `+b+a`

associative operations
(bit-wise operations are safe, otherwise `unsafe_math`)
- `a + (b + c)`       => `(a + b) + c`
- `(n + 2) + 3`       => `5 + n`
- `(2 * n) * 3`       => `6 * n`
- `(a | 1) | (2 | d)` => `(3 | a) | b`

fixes #412
2017-03-03 18:04:32 +08:00
Alex Lam S.L
c8e61448cb Merge pull request #1541 from alexlamsl/harmony-v2.8.5
Merging from master for 2.8.5
2017-03-03 07:30:28 +08:00
alexlamsl
f704e9b65c fix destructing crash in reduce_vars
fixes #1531
2017-03-03 07:23:46 +08:00
alexlamsl
0b77d861a8 Merge branch 'master' into harmony-v2.8.5 2017-03-03 07:17:52 +08:00
Alex Lam S.L
b5e0e8c203 facilitate fix for #1531 (#1542) 2017-03-03 07:12:24 +08:00
Alex Lam S.L
e5cb9275df v2.8.5 2017-03-03 05:14:21 +08:00
Alex Lam S.L
17b81350d4 fix chained assignment with unused (#1540)
When #1450 optimises `a=b=42`, it stops after the first variable even if both are unused.

fixes #1539
2017-03-03 04:45:20 +08:00
kzc
4d63d4f5b3 collapse_vars should not replace constant in for-in init section (#1538)
fixes #1537
2017-03-03 03:51:15 +08:00
Alex Lam S.L
70d72ad806 properly cover all cases of for-in loop variables (#1536) 2017-03-03 02:39:57 +08:00
Alex Lam S.L
fe9227a41b fix reference marking in for-in loops (#1535)
fixes #1533
2017-03-03 00:56:06 +08:00
Alex Lam S.L
b49e142a26 disable do{...}while(false) optimisation (#1534)
- fails to handle `break` in body

fixes #1532
2017-03-03 00:54:41 +08:00
kzc
ee3b39b909 optimize trivial IIFEs returning constants (#1530) 2017-03-02 15:11:40 +08:00
Alex Lam S.L
9699ffb1af trim unused invocation parameters (#1526) 2017-03-02 11:33:59 +08:00
Alex Lam S.L
fdc9b9413b minor improvement to string optimisation (#1514)
- "" + "a"     => "a"
- "" + a + "b" => a + "b"
- "a" + ""     => "a" (improving on #45)
2017-03-02 11:31:39 +08:00
Alex Lam S.L
e27dab7e7c Merge pull request #1528 from alexlamsl/harmony-v2.8.4
Merging from master for 2.8.4
2017-03-02 11:22:06 +08:00
alexlamsl
80f3ad3ce0 Merge branch 'master' into harmony-v2.8.4 2017-03-02 11:16:55 +08:00
Alex Lam S.L
40ceddb48a v2.8.4 2017-03-02 00:24:49 +08:00
Alex Lam S.L
7aa69117e1 fix corner cases in reduce_vars (#1524)
Avoid variable substitution in the following cases:
- use of variable before declaration
- declaration within conditional code blocks
- declaration within loop body

fixes #1518
fixes #1525
2017-03-02 00:20:53 +08:00
Alex Lam S.L
bff7ad67bb v2.8.3 2017-03-01 15:28:46 +08:00
Alex Lam S.L
c2334baa48 fix crash on missing props to string_template() (#1523)
Patched up `make_node()` without `orig`.

There may be other cases where `start` could be missing, so make it print "undefined" instead of crashing.

fixes #1518
2017-03-01 15:25:26 +08:00
Alex Lam S.L
22f7af205d Merge pull request #1521 from alexlamsl/harmony-v2.8.2
Merging from master for 2.8.2
2017-03-01 11:13:32 +08:00
alexlamsl
8a7a4749c7 Merge branch 'master' into harmony-v2.8.2 2017-03-01 11:06:33 +08:00
Alex Lam S.L
514fc68f4f Merge pull request #1509 from alexlamsl/harmony-2.8.0
Merging from master for 2.8.0
2017-02-28 23:14:25 +08:00
alexlamsl
478aaab469 fix parser test
not sure if `start.pos` is correct, but oh well
2017-02-28 14:08:31 +08:00
alexlamsl
ab217539e9 restore sourceMappingURL in test 2017-02-28 13:23:02 +08:00
alexlamsl
a942dc07c4 fix parser tests
update exception messages
2017-02-28 03:58:01 +08:00
kzc
a0eaff750d fix parsing of arrow function with bind
fixes #1510
2017-02-28 02:47:33 +08:00
alexlamsl
57777b6cfa Merge branch 'master' into harmony-2.8.0 2017-02-28 02:28:58 +08:00
kzc
8d205f7f39 fix parser handling of comments 2017-02-27 14:54:47 +08:00
alexlamsl
bc9bfd15a2 fix test 2017-02-27 11:39:48 +08:00
alexlamsl
9fc1c4b3b5 update test
top-level block-variables not within blocks are global variables
2017-02-27 06:23:12 +08:00
alexlamsl
c59bf5e8d8 fix SymbolDef.global
properly compute for top-level block-variables
2017-02-27 06:20:08 +08:00
alexlamsl
d2d3a6e065 fix double-descend()
for `AST_Export` in `AST_Toplevel.figure_out_scope()`
2017-02-27 06:06:09 +08:00
alexlamsl
7755733716 fix "Starting destructuring."
commit 32f76f7ff does not take into account `AST_SymbolFunarg` is also `AST_SymbolVar`, so don't need to call `AST_Scope.def_variable()` twice
2017-02-27 05:30:18 +08:00
alexlamsl
b3a987b0df fix up drop_unused() 2017-02-27 05:11:01 +08:00
alexlamsl
88a338f29e Merge branch 'master' into harmony-2.8.0 2017-02-27 04:37:48 +08:00
Anthony Van de Gejuchte
07734b000a Destructuring consistency fixes (#1417)
- Use AST_Destructuring for lhf assignment patterns
- Use AST_DefaultAssign for default assignments
- Add more checks for lhs expressions
- Add lots of testing
- Cleanup ast (e.g. remove default property)
- Fix #1402 based on a patch from @kzc
- Refine spread allowance in array destructring pattern
- Add destructuring AST tree checker
2017-02-24 08:49:19 +08:00
Anthony Van de Gejuchte
85c1cba760 Remove duplicated code (#1456)
[ES6] Remove duplicated code
2017-02-24 08:48:13 +08:00
Richard van Velzen
4bd31607f6 Merge branch 'master' into harmony 2017-01-26 13:02:22 +01:00
Anthony Van de Gejuchte
4728bc73ad Allow parsing regexp after arrow token (#1439) 2017-01-26 12:06:46 +01:00
Anthony Van de Gejuchte
52ce9a333c Fix compression with unused containing destructuring 2017-01-19 21:04:28 +01:00
kzc
abbeb266b5 [ES6] output parens for yield when parented by AST_Dot or AST_Sub (#1419) 2017-01-19 17:15:59 +01:00
Anthony Van de Gejuchte
b11c5151bc Fix regression with non-ascii function identifiers
Regression since 110a1ac885
2017-01-19 16:47:37 +01:00
Richard van Velzen
962b1f3d40 Merge branch 'master' into harmony 2016-11-30 18:59:32 +01:00
Richard van Velzen
3ee46e91e8 Merge branch 'master' into harmony 2016-11-29 22:32:49 +01:00
Richard van Velzen
ee26e7f11b Merge branch 'master' into harmony 2016-11-29 20:50:27 +01:00
Anthony Van de Gejuchte
937f534392 Fix flag name in readme 2016-11-29 20:44:22 +01:00
Anthony Van de Gejuchte
1b2c02c944 Fix nlb property for template strings tokens starting with nlb
Also add .gitattributes to checkout lf eol style
2016-11-29 20:36:00 +01:00
Anthony Van de Gejuchte
0aa526e72c Do not allow arrow functions in the middle of an expression 2016-11-29 20:32:05 +01:00
Anthony Van de Gejuchte
c2112d5886 Fix case where a lonely var is used as computed property 2016-11-29 20:19:01 +01:00
Anthony Van de Gejuchte
5f6825f9ec Introduce is_block_scope to AST_Node to determine block scope.
Will return false if AST_Node is instance of AST_Scope for now.
2016-10-24 21:28:32 +02:00
Anthony Van de Gejuchte
7e80a979a7 Remove AST_ObjectComputedKeyVal 2016-10-23 22:12:30 +02:00
Richard van Velzen
b7bb706150 Merge branch 'master' into harmony 2016-10-23 22:11:27 +02:00
Anthony Van de Gejuchte
32c2cc33bb Improve binding patterns for arrow functions 2016-10-23 21:13:12 +02:00
Anthony Van de Gejuchte
947b8750e8 Make classes implicitly strict mode 2016-10-17 20:24:38 +02:00
kzc
88f6ff38d1 [ES6] fix template string escaping of \${...} 2016-10-01 11:32:36 +02:00
kzc
4198095a9c [ES6] fix parsing spread arguments that are expressions 2016-09-29 13:34:22 -04:00
Anthony Van de Gejuchte
13ed445607 Improve support for binding pattern
Including improvements for parameters, variable assignment and
catch parameter.
2016-09-05 17:48:48 +02:00
Richard van Velzen
1db50c3b16 Don't parenthesize arrow functions in parameter lists 2016-09-02 09:35:31 +02:00
Richard van Velzen
7f6b5d662b Merge branch 'master' into harmony 2016-08-30 15:16:23 +02:00
Anthony Van de Gejuchte
1c15d0db45 Fix quoting of properties
- Make AST_ConciseMethod child of AST_ObjectProperty.
- Fix some typos.
2016-08-26 15:06:24 +02:00
Richard van Velzen
67461666dc Merge branch 'master' into harmony 2016-08-17 21:30:35 +02:00
Richard van Velzen
45d81f881b Merge branch 'master' into harmony 2016-08-17 20:21:38 +02:00
Richard van Velzen
8c7d23dfb1 Merge branch 'master' into harmony 2016-08-17 08:50:31 +02:00
Richard van Velzen
7fa0dbdeb9 Ignore default reserved properties in compress test 2016-08-15 09:54:15 +02:00
Richard van Velzen
c644c1292d Merge branch 'master' into harmony 2016-08-15 09:09:04 +02:00
kzc
d224d71b8d [ES6] Fix handling of semicolons in export parse. 2016-08-14 21:43:24 +02:00
Anthony Van de Gejuchte
27d3669800 Don't allow escaped surrogated identifiers + introduce ascii_identifiers
Don't use 2 characters for surrogates in identifiers because there is
support for the \u{} syntax when escaped identifiers were introduced.

Also catch eof errors while reading identifier names

Introduce ascii_identifiers:

By setting ascii_identifiers to undefined (default value),
ascii_identifiers will print identifiers using the same setting as
ascii_only within the limits of the ecmascript 6 grammar.

ascii_identifiers accept true and false, allowing identifiers to be
printed under different settings than strings with the ascii_only setting.
2016-08-14 21:36:06 +02:00
Anthony Van de Gejuchte
110a1ac885 Make distinction between * method and * operator
Also add quotes to properties when necessary,
this might be the case if the name isn't a valid
identifier
2016-07-29 21:31:08 +02:00
Anthony Van de Gejuchte
3f8fc3a316 Fix computed getters + cleanup AST 2016-07-21 18:21:46 +02:00
Anthony Van de Gejuchte
88384cf351 Add more globals, whereof most defined after es5.1
Also do not pollute env with mocks replacing standard globals
2016-07-21 16:52:04 +02:00
Anthony Van de Gejuchte
72a9d799b6 Various property fixes
* Implement getter/setter with computed value
* Fix parsing getter/setter after static or generator token
* Allow storing expressions for computed expression in AST_SymbolMethod
* Allow get and set in shorthand properties in object literals

Fixes #1094, #1146 and #1221
2016-07-21 16:50:32 +02:00
Anthony Van de Gejuchte
766fafda8b Don't remove empty generators passed as parameter 2016-07-19 18:13:07 +02:00
kzc
842ac27efb [ES6] Get compress and global_defs working for AST_Class 2016-07-17 19:56:02 +02:00
Anthony Van de Gejuchte
0af42d1831 Template fixes
* Fixes #1147: template strings not obeying -b ascii_only true
* Allow evaluation of template expressions by adding optimizers and
  walkers
* Make sure tagged templates are never changed
* Remove template tokenizer in parser, add template tokenizer in
  tokenizer. It is using a brace counter to track brace position of
  templates
* Add tokens `template_head` and `template_substitution` but parsing
  tokens stays mostly the same
* Do not output strings anymore in AST_TemplateString, instead use
  AST_TemplateSegment
* Fix parsing tagged templates, allowing multiple templates behind
  as spec allows this

These changes don't influence tagged templates because raw content
may influence code execution, however they are safe to do in normal
templates:
* Allow basic string concatenation of templates where possible
* Allow custom character escape style similar to strings, except in
  tagged templates

Note that expressions are still compressed in tagged templates.

Optional things that may be improved later:
* Custom quote style for templates if it doesn't have expressions.
  Making it obey the quote_style option if this is the case.
2016-07-17 00:36:42 +02:00
Anthony Van de Gejuchte
ff7f6139ba Improve multi-line comment parsing
* Make sure comments are skipped correctly with surrogates
* Fix regression in multiline comments with nlb
2016-07-12 00:08:35 +02:00
Richard van Velzen
0db7caf13b Merge branch 'master' into harmony 2016-07-03 21:39:00 +02:00
Anthony Van de Gejuchte
d9bc6f303c Fix output arrow function with 1 param with default value
Fixes #1090
2016-07-03 21:37:53 +02:00
Anthony Van de Gejuchte
6fd9b338dd Merge branch 'master' into harmony 2016-07-03 21:35:00 +02:00
Anthony Van de Gejuchte
d8d4e71b9e Fix uses_with/uses_eval/directives state in block scope 2016-07-01 15:43:17 +02:00
Anthony Van de Gejuchte
fb2f8d1a51 Add reserved words to list unescapable keywords
Additionals:
* Update list reserved keywords
2016-06-30 22:47:44 +02:00
Anthony Van de Gejuchte
54a783ba84 Add ecma5 flag for codegen 2016-06-30 22:47:44 +02:00
Anthony Van de Gejuchte
63c432f4fa Extend unicode support
* Support \u{xxxx} syntax
 * Add support for surrogate pairs
 * Allow identifiers to have unicode escape sequence
2016-06-30 22:47:44 +02:00
Anthony Van de Gejuchte
07785d0003 Throw error if new.target is like new.foo 2016-06-25 19:32:53 +02:00
Anthony Van de Gejuchte
6eaeb19a4a Add exponentiation operator 2016-06-22 12:23:37 +02:00
Anthony Van de Gejuchte
2246c79318 Merge branch 'master' into fix-harmony 2016-06-20 19:21:25 +02:00
Anthony Van de Gejuchte
dda58244b6 Fixes to prevent failing tests after merging master
* Add missing quote properties to AST_ObjectKeyVal
 * Avoid test results being interpret as directives
2016-06-20 15:02:09 +02:00
Anthony Van de Gejuchte
ca04508cd1 Restrict yield outside generators in strict mode
* Move some yield/generic tests from compress/harmony.js to
  compress/yield.js
 * Adjust error messages to conform ecmascript standards
2016-06-19 21:03:36 +02:00
Anthony Van de Gejuchte
6b03b800b3 Only last parameter between parentheses can have spread 2016-06-19 20:51:29 +02:00
Anthony Van de Gejuchte
f9cab7ad61 Allow expand in array literals 2016-06-19 20:49:18 +02:00
Richard van Velzen
0a3d780327 Merge branch 'master' into harmony 2016-06-12 17:29:42 +02:00
Anthony Van de Gejuchte
b0555a123a Fix newline handling after yield
YieldExpressions can only be defined as:
 * `yield`
 * `yield` [no nlb] AssignmentExpression
 * `yield` [no nlb] `*` AssignmentExpression
2016-06-11 21:41:16 +02:00
Richard van Velzen
fa29344781 Merge branch 'master' into harmony 2016-06-09 22:29:52 +02:00
Anthony Van de Gejuchte
dcfc514c38 Improve yield support and restrict usage of strict
- Partially reverting 91cdb93e57 and eaf3911c31 and reimplement
- Add generators support for objects and classes
- Only classes can have static methods so restrict use of it

Special thanks to @rvanvelzen and @kzc for reviewing this patch and
providing constructive feedback over and over again.
2016-06-09 22:22:15 +02:00
Anthony Van de Gejuchte
8ad8d7b717 Add Symbol to builtins 2016-05-24 17:57:18 +02:00
Richard van Velzen
0357e5923f Merge branch 'master' into harmony 2016-05-24 17:56:20 +02:00
Richard van Velzen
f63803e3e3 Merge branch 'master' into harmony 2016-05-16 09:53:13 +02:00
Richard van Velzen
63be1f3a4d Only allow var definitions to be moved into the for-init clause
Fixes #1079
2016-05-15 21:00:51 +02:00
Richard van Velzen
e36e07fa77 Merge branch 'master' into harmony 2016-05-04 20:13:35 +02:00
Richard van Velzen
d1b4f61f93 Merge pull request #1059 from not-an-aardvark/harmony
Avoid syntax error in yield assignments
2016-04-26 11:51:13 +02:00
not-an-aardvark
5b893c8ec3 Avoid syntax error in yield assignments (fixes #1054) 2016-04-25 19:14:44 -04:00
Richard van Velzen
8571a08a93 Do not attempt evaluating class expressions
Broadly the same as function expressions - these actually are statements but
we're limited by the inheritance tree.

Fixes #1044
2016-04-19 20:01:26 +02:00
Richard van Velzen
68cc14f846 Fixups after merge 2016-04-18 15:51:32 +02:00
Richard van Velzen
f94497d1d6 Merge branch 'master' into harmony 2016-04-18 15:50:35 +02:00
Richard van Velzen
eaf3911c31 Consider yield expressions as having side-effects
See #1043
2016-04-13 14:39:49 +02:00
Darío Javier Cravero
91cdb93e57 Implement harmony generators and yield
Uses #716's implementation and adds tests.

Fixes #716.
2016-04-13 14:22:08 +02:00
Fábio Santos
634f231b78 First class block scope
- Make let, const, and class symbols be declared in a block scope.
- Piggy back on existing catch symbol implementation to get block-aware mangling working
- Make sure unused block-scoped declarations can be dropped
- Don't eliminate a block if it has a block-scoped declaration
- Remove silly empty anonymous blocks left over from drop_unused
- AST_Toplevel now gets to call drop_unused too, since block-scoped variables aren't global!
- Don't consider block declarations global
2016-03-27 19:40:20 +02:00
Fábio Santos
6702cae918 fix #1021 2016-03-27 12:21:39 +01:00
Fábio Santos
6d2f77c180 fix #1003 by removing AST_ObjectSymbol and using AST_ObjectKeyVal for the same effect 2016-03-14 13:42:50 +01:00
Fábio Santos
accca2445f fix crash: Import statements don't abort 2016-03-14 12:54:05 +01:00
Fábio Santos
0bc4f6edb4 Don't mangle exported symbols 2016-03-14 12:54:05 +01:00
Fábio Santos
ce84a706a3 Implement the export statement 2016-03-14 12:54:05 +01:00
Fábio Santos
86b5248837 Mangling externally imported names by using aliasing 2016-03-14 12:54:05 +01:00
Fábio Santos
59e1601fb8 importing names in the modules, not just default imports 2016-03-14 12:54:05 +01:00
Fábio Santos
d35a9e7839 Importing names from places 2016-03-14 12:54:05 +01:00
Fábio Santos
0465bd270d Starting out the import statement 2016-03-14 12:54:05 +01:00
viclm
6780d0906c Fix eager parsing of arrow functions for non-punc tokens 2016-03-10 22:18:48 +01:00
Darío Javier Cravero
0b303379c0 fix: don't fail if definition is undefined
Running `uglifyjs --verbose --compress --mangle --screw-ie8 class.js`
with
`class.js`:
```
class Foo {
  bar() {
  }
}
```
Fails with:
```
undefined:4041
  return this.definition().unmangleable(options);
TypeError: Cannot read property 'unmangleable' of undefined
...
```
2016-02-10 10:17:32 +01:00
Fábio Santos
d7ec2ecc12 Fix #931: Create arrow functions in maybe_assign so that they can be used in assignments 2016-02-09 00:02:23 +00:00
Richard van Velzen
2827fa8699 Merge branch 'harmony' of github.com:mishoo/UglifyJS2 into harmony 2016-01-19 19:22:35 +01:00
Richard van Velzen
c80ec625ec Add test for bad template string parsing 2016-01-19 19:22:22 +01:00
Fugiman
5e78f20f1c Remove duplicate error message 2016-01-19 19:22:22 +01:00
Fugiman
1f75232062 Fix template string parsing 2016-01-19 19:22:22 +01:00
Fábio Santos
028ff64e9a Default values inside destructurings 2016-01-19 19:22:22 +01:00
Fábio Santos
7a8cffd631 Move the idea of a symbol having a default value up the class chain. 2016-01-19 19:22:22 +01:00
Fábio Santos
5b553aafe2 Destructuring parameters with defaults. function x({ foo, bar } = {}) { } 2016-01-19 19:22:22 +01:00
Fábio Santos
084437bc6d Non-destructuring default parameters 2016-01-19 19:22:22 +01:00
Richard van Velzen
1cd9a2df9a Merge pull request #872 from fabiosantoscode/feature/harmony-defaults
Feature/harmony defaults
2016-01-05 21:39:23 +01:00
Richard van Velzen
7f3dbb6df7 Merge branch 'master' into harmony 2015-12-26 17:59:38 +01:00
Richard van Velzen
e4d73d8b7c Merge pull request #870 from fabiosantoscode/feature/harmony-class
Harmony: classes
2015-12-07 18:59:07 +01:00
Fábio Santos
8220dbbea0 Default values inside destructurings 2015-11-22 19:04:42 +00:00
Fábio Santos
59e999597e Move the idea of a symbol having a default value up the class chain. 2015-11-22 19:00:54 +00:00
Fábio Santos
cbcb3ac44e Destructuring parameters with defaults. function x({ foo, bar } = {}) { } 2015-11-22 18:02:51 +00:00
Fábio Santos
f07ab4666f Non-destructuring default parameters 2015-11-22 17:40:05 +00:00
Fábio Santos
a800356ad0 Implement new.target 2015-11-21 14:48:23 +00:00
Fábio Santos
e076abdbf2 Mangle class names correctly 2015-11-21 13:59:18 +00:00
Fábio Santos
425613b0d2 mangle class names 2015-11-21 12:20:20 +00:00
Fábio Santos
69da8e53e0 Separate class expressions from class declarations and their symbols like defuns 2015-11-21 09:17:32 +00:00
Fábio Santos
bb6b3a773a Make AST_Class inherit AST_Scope instead of AST_Object
This is one of those days I'd love to use multiple inheritance.

An AST_Class has lots of common with AST_Object, but unfortunately
`instanceof AST_Scope` is used very, very much, and a class has its name
inside its own special pocket scope. This compels me to make AST_Class
inherit Scope instead.

It looks like, although there is much in common with AST_Object,
`instanceof AST_Object` seldom are made, perhaps because it is less
often necessary to traverse an object than a scope.
2015-11-20 19:34:10 +00:00
Fábio Santos
364d20f8fb Add mangle = { ...mangleopts } option to tests. 2015-11-20 18:11:17 +00:00
Richard van Velzen
392ac4ff31 Merge branch 'master' into harmony 2015-10-28 20:38:07 +01:00
Fábio Santos
9ffed2bea6 static properties 2015-10-27 12:24:37 +00:00
Fábio Santos
5f7cb6939c Starting ES6 classes 2015-10-27 12:24:37 +00:00
Fábio Santos
64e7a00399 Accept keyword names as concise method names 2015-10-27 09:31:16 +01:00
Fábio Santos
c99eaae360 Make concise methods work with propmangle 2015-10-27 09:31:16 +01:00
Fábio Santos
34213ea2f8 Create a new symbol for methods' names 2015-10-27 09:31:16 +01:00
Fábio Santos
da8c428a07 Just making sure that concise methods are separated by commas. When classes come, they won't be necessary. 2015-10-27 09:31:16 +01:00
Fábio Santos
0d8dea9538 start concise methods 2015-10-27 09:31:16 +01:00
Richard van Velzen
2babe737e0 Merge pull request #844 from fabiosantoscode/harmony-allow-of
Harmony: allow use of `of` as a name.
2015-10-27 09:26:51 +01:00
Fábio Santos
2cce61c564 Allow 'of' to be a name. 2015-10-26 20:56:59 +00:00
Richard van Velzen
246ec416c0 Merge branch 'master' into harmony 2015-10-20 21:58:58 +02:00
Richard van Velzen
6be9c752d5 Merge branch 'master' into harmony 2015-10-20 20:12:10 +02:00
Fábio Santos
76ed083e47 Using single quotes 2015-10-12 21:39:19 +01:00
Fábio Santos
b31918bbf0 computed properties 2015-10-12 21:38:20 +01:00
Richard van Velzen
b14496c742 Merge branch 'master' into harmony
Conflicts:
	lib/compress.js
2015-10-12 08:54:44 +02:00
Richard van Velzen
991fa99655 Merge branch 'master' into harmony 2015-09-13 14:17:45 +02:00
Fábio Santos
3d7f73114d Add a test to make sure future generations don't hoist lets 2015-09-13 14:15:53 +02:00
Fábio Santos
dde9e293df parse, output the let statement 2015-09-13 14:15:53 +02:00
Richard van Velzen
34685a6f55 Merge pull request #794 from fabiosantoscode/feature/harmony-template-strings-2
Harmony: template strings
2015-09-08 21:23:41 +02:00
Richard van Velzen
9812c826e0 Merge pull request #795 from fabiosantoscode/harmony-fix-cannot-destructure-crash
Fix crash, remove unused code and state variable.
2015-09-06 17:05:34 +02:00
Fábio Santos
2fac2bbfe4 Remove unused state variable in_parameters, and also remove unreachable code (try_an_object always returned an object!) 2015-09-05 23:01:29 +01:00
Fábio Santos
242c61be94 prefixed template strings, like "String.rawfoo\nbar". 2015-09-05 22:48:38 +01:00
Fábio Santos
e1cb1a0e3c Parse and output ES6 template strings. Yikes! 2015-09-05 22:32:57 +01:00
Richard van Velzen
af22b9c657 Merge pull request #768 from fabiosantoscode/feature/harmony-destructuring-expression
Feature/harmony destructuring expression
2015-08-25 19:00:36 +02:00
Fábio Santos
adee5023c0 What about --mangle-props being on and --mangle being off? 2015-08-25 17:52:51 +01:00
Fábio Santos
7ee8f3512e play nice with propmangle 2015-08-25 17:49:29 +01:00
Fábio Santos
dc5db9b6ca Starting destructuring expressions 2015-08-25 17:49:27 +01:00
Fábio Santos
079aaa0d48 Tolerate expansions in vardefs, too! 2015-08-21 12:04:26 +02:00
Fábio Santos
d4f17f29ae Destructuring vardef in for..of and for..in 2015-08-21 12:04:26 +02:00
Fábio Santos
e99bc914ca Do not mangle a name if it is in a destructuring vardef. 2015-08-21 12:04:26 +02:00
Fábio Santos
025d34bfa2 Add holes in destructuring defs, also make them nestable 2015-08-21 12:04:26 +02:00
Fábio Santos
c44c2d6c21 Parse and compress destructuring VarDefs 2015-08-21 12:04:26 +02:00
Fábio Santos
824ecfb8a2 A little refactoring. Add a new function to get all symbols in a destructuring. 2015-08-21 12:04:26 +02:00
Fábio Santos
ceebc466b9 prepare AST_Destructuring for the Ents 2015-08-21 12:04:26 +02:00
Richard van Velzen
35b31bdd4e Merge branch 'master' into harmony 2015-08-21 11:58:35 +02:00
Richard van Velzen
c8b82583d2 Merge pull request #773 from fabiosantoscode/harmony-typeof-arrows
Fix evaluating the typeof an arrow function.
2015-08-21 11:51:42 +02:00
Richard van Velzen
9f9179ba1a Merge pull request #774 from fabiosantoscode/feature/harmony-symbol
remove Symbol's argument when we're unsafe and Symbol is undeclared
2015-08-21 11:51:02 +02:00
Richard van Velzen
872231a0ca Merge pull request #775 from fabiosantoscode/feature/binary-literals
Parse ES6 number literals, round 2
2015-08-21 11:50:39 +02:00
Fábio Santos
36420183fd s/binary/number/g 2015-08-17 16:23:43 +01:00
Fábio Santos
a8f8aa518b Add new-style octal literals and make the B and the O case insensitive. 2015-08-17 11:50:56 +01:00
Fábio Santos
4c12cccff9 remove Symbol's argument when we're unsafe and it's undeclared 2015-08-14 22:44:16 +01:00
Fábio Santos
dcce4e5c66 Fix evaluating the typeof an arrow function. Using evaluate on used to cause a crash. 2015-08-14 22:05:42 +01:00
Richard van Velzen
56c0b834d6 Merge pull request #771 from fabiosantoscode/feature/binary-literals
Parse binary number literals
2015-08-14 14:59:55 +02:00
Fábio Santos
6f864402d3 Parse binary number literals 2015-08-14 03:24:54 +01:00
Richard van Velzen
8909e9e1cb Merge pull request #763 from fabiosantoscode/feature/harmony-super
Feature/harmony super
2015-08-07 08:54:20 +02:00
Fábio Santos
e80ed38772 Super! 2015-08-07 02:44:53 +01:00
Fábio Santos
9863f0efa3 expand parameters
Conflicts:
	test/compress/harmony.js
2015-08-05 21:15:23 +02:00
Richard van Velzen
e8664e63ef Merge branch 'master' into harmony 2015-08-05 21:13:11 +02:00
Fábio Santos
ddd30eeaaa Uglifyjs already supports super as an implicit global! Just adding a test to indicate that. 2015-08-05 11:49:37 +01:00
Fábio Santos
a68953c491 => with destructuring arguments. Requires a lot of parser changes 2015-08-04 00:57:53 +01:00
Fábio Santos
fa5c4f2d03 Adding arrow functions 2015-08-04 00:57:53 +01:00
Fábio Santos
9d7d365c2b for...of 2015-07-29 15:10:54 +02:00
Fábio Santos
ad344c5be3 Add a test to verify that destructuring arguments work with #203 code 2015-07-29 14:54:45 +02:00
Fábio Santos
96b89e34a3 test that names used in destructurings don't get hoisted 2015-07-29 14:54:45 +02:00
Fábio Santos
4644becb9b do not support destructuring arguments and ngInject 2015-07-29 14:54:45 +02:00
Fábio Santos
f7460166dd remove trace statement 2015-07-29 14:54:45 +02:00
Fábio Santos
32f76f7ff8 Starting destructuring. 2015-07-29 14:54:45 +02:00
187 changed files with 33150 additions and 10409 deletions

20
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,20 @@
**Bug report or feature request?**
<!-- Note: sub-optimal but correct code is not a bug -->
**ES5 or ES6+ input?**
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
**Uglify version (`uglifyjs -V`)**
**JavaScript input** <!-- ideally as small as possible -->
**The `uglifyjs` CLI command executed or `minify()` options used.**
**JavaScript output or error produced.**
<!--
Note: `uglify-js` only supports ES5.
Those wishing to minify ES6 should use `uglify-es`.
-->

View File

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

1374
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +0,0 @@
#! /usr/bin/env node
"use strict";
var U2 = require("../tools/node");
var fs = require("fs");
var yargs = require("yargs");
var ARGS = yargs
.describe("o", "Output file")
.argv;
var files = ARGS._.slice();
var output = {
vars: {},
props: {}
};
if (ARGS.o) try {
output = JSON.parse(fs.readFileSync(ARGS.o, "utf8"));
} catch(ex) {}
files.forEach(getProps);
if (ARGS.o) {
fs.writeFileSync(ARGS.o, JSON.stringify(output, null, 2), "utf8");
} else {
console.log("%s", JSON.stringify(output, null, 2));
}
function getProps(filename) {
var code = fs.readFileSync(filename, "utf8");
var ast = U2.parse(code);
ast.walk(new U2.TreeWalker(function(node){
if (node instanceof U2.AST_ObjectKeyVal) {
add(node.key);
}
else if (node instanceof U2.AST_ObjectProperty) {
add(node.key.name);
}
else if (node instanceof U2.AST_Dot) {
add(node.property);
}
else if (node instanceof U2.AST_Sub) {
addStrings(node.property);
}
}));
function addStrings(node) {
var out = {};
try {
(function walk(node){
node.walk(new U2.TreeWalker(function(node){
if (node instanceof U2.AST_Seq) {
walk(node.cdr);
return true;
}
if (node instanceof U2.AST_String) {
add(node.value);
return true;
}
if (node instanceof U2.AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function add(name) {
output.props[name] = true;
}
}

View File

@@ -3,629 +3,400 @@
"use strict";
var UglifyJS = require("../tools/node");
var sys = require("util");
var yargs = require("yargs");
var fs = require("fs");
var path = require("path");
var async = require("async");
var acorn;
var screw_ie8 = true;
var ARGS = yargs
.usage("$0 input1.js [input2.js ...] [options]\n\
Use a single dash to read input from the standard input.\
\n\n\
NOTE: by default there is no mangling/compression.\n\
Without [options] it will simply parse input files and dump the AST\n\
with whitespace and comments discarded. To achieve compression and\n\
mangling you need to use `-c` and `-m`.\
")
.describe("source-map", "Specify an output file where to generate source map.")
.describe("source-map-root", "The path to the original source to be included in the source map.")
.describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map.")
.describe("source-map-inline", "Write base64-encoded source map to the end of js output. Disabled by default")
.describe("source-map-include-sources", "Pass this flag if you want to include the content of source files in the source map as sourcesContent property.")
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
.describe("screw-ie8", "Do not support Internet Explorer 6/7/8. This flag is enabled by default.")
.describe("support-ie8", "Support non-standard Internet Explorer 6/7/8 javascript. Note: may generate incorrect code for try/catch in ES5 compliant browsers.")
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
.describe("p", "Skip prefix for original filenames that appear in source maps. \
For example -p 3 will drop 3 directories from file names and ensure they are relative paths. \
You can also specify -p relative, which will make UglifyJS figure out itself the relative paths between original sources, \
the source map and the output file.")
.describe("o", "Output file (default STDOUT).")
.describe("b", "Beautify output/specify output options.")
.describe("m", "Mangle names/pass mangler options.")
.describe("r", "Reserved names to exclude from mangling.")
.describe("c", "Enable compressor/pass compressor options. \
Pass options like -c hoist_vars=false,if_return=false. \
Use -c with no argument to use the default compression options.")
.describe("d", "Global definitions")
.describe("e", "Embed everything in a big function, with a configurable parameter/argument list.")
.describe("comments", "Preserve copyright comments in the output. \
By default this works like Google Closure, keeping JSDoc-style comments that contain \"@license\" or \"@preserve\". \
You can optionally pass one of the following arguments to this flag:\n\
- \"all\" to keep all comments\n\
- a valid JS RegExp like `/foo/`or `/^!/` to keep only matching comments.\n\
\
Note that currently not *all* comments can be kept when compression is on, \
because of dead code removal or cascading statements into sequences.")
.describe("preamble", "Preamble to prepend to the output. You can use this to insert a \
comment, for example for licensing information. This will not be \
parsed, but the source map will adjust for its presence.")
.describe("stats", "Display operations run time on STDERR.")
.describe("acorn", "Use Acorn for parsing.")
.describe("spidermonkey", "Assume input files are SpiderMonkey AST format (as JSON).")
.describe("self", "Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all)")
.describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
.describe("export-all", "Only used when --wrap, this tells UglifyJS to add code to automatically export all globals.")
.describe("lint", "Display some scope warnings")
.describe("v", "Verbose")
.describe("V", "Print version number and exit.")
.describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
.describe("reserved-file", "File containing reserved names")
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
.describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)")
.describe("mangle-regex", "Only mangle property names matching the regex")
.describe("name-cache", "File to hold mangled names mappings")
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
.describe("wrap-iife", "Wrap IIFEs in parenthesis. Note: this disables the negate_iife compression option")
.alias("p", "prefix")
.alias("o", "output")
.alias("v", "verbose")
.alias("b", "beautify")
.alias("m", "mangle")
.alias("c", "compress")
.alias("d", "define")
.alias("r", "reserved")
.alias("V", "version")
.alias("e", "enclose")
.alias("q", "quotes")
.string("source-map")
.string("source-map-root")
.string("source-map-url")
.string("b")
.string("beautify")
.string("m")
.string("mangle")
.string("mangle-props-debug")
.string("c")
.string("compress")
.string("d")
.string("define")
.string("e")
.string("enclose")
.string("comments")
.string("wrap")
.string("p")
.string("prefix")
.string("name-cache")
.array("reserved-file")
.array("pure-funcs")
.boolean("expr")
.boolean("source-map-inline")
.boolean("source-map-include-sources")
.boolean("screw-ie8")
.boolean("support-ie8")
.boolean("export-all")
.boolean("self")
.boolean("v")
.boolean("verbose")
.boolean("stats")
.boolean("acorn")
.boolean("spidermonkey")
.boolean("dump-spidermonkey-ast")
.boolean("lint")
.boolean("V")
.boolean("version")
.boolean("noerr")
.boolean("bare-returns")
.boolean("keep-fnames")
.boolean("reserve-domprops")
.boolean("wrap-iife")
.wrap(80)
.argv
;
normalize(ARGS);
if (ARGS.noerr) {
UglifyJS.DefaultsError.croak = function(msg, defs) {
print_error("WARN: " + msg);
};
}
if (ARGS.version || ARGS.V) {
var json = require("../package.json");
print(json.name + ' ' + json.version);
process.exit(0);
}
if (ARGS.ast_help) {
var desc = UglifyJS.describe_ast();
print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
process.exit(0);
}
if (ARGS.h || ARGS.help) {
print(yargs.help());
process.exit(0);
}
if (ARGS.acorn) {
acorn = require("acorn");
}
var COMPRESS = getOptions("c", true);
var MANGLE = getOptions("m", true);
var BEAUTIFY = getOptions("b", true);
var RESERVED = null;
if (ARGS.reserved_file) ARGS.reserved_file.forEach(function(filename){
RESERVED = UglifyJS.readReservedFile(filename, RESERVED);
// 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);
});
if (ARGS.reserve_domprops) {
RESERVED = UglifyJS.readDefaultReservedFile(RESERVED);
}
var fs = require("fs");
var info = require("../package.json");
var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node");
if (ARGS.d) {
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
}
if (ARGS.pure_funcs) {
if (COMPRESS) COMPRESS.pure_funcs = ARGS.pure_funcs;
}
if (ARGS.r) {
if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
}
if (RESERVED && MANGLE) {
if (!MANGLE.except) MANGLE.except = RESERVED.vars;
else MANGLE.except = MANGLE.except.concat(RESERVED.vars);
}
function readNameCache(key) {
return UglifyJS.readNameCache(ARGS.name_cache, key);
}
function writeNameCache(key, cache) {
return UglifyJS.writeNameCache(ARGS.name_cache, key, cache);
}
function extractRegex(str) {
if (/^\/.*\/[a-zA-Z]*$/.test(str)) {
var regex_pos = str.lastIndexOf("/");
return new RegExp(str.substr(1, regex_pos - 1), str.substr(regex_pos + 1));
} else {
throw new Error("Invalid regular expression: " + str);
}
}
if (ARGS.quotes === true) {
ARGS.quotes = 3;
}
if (ARGS.mangle_props === true) {
ARGS.mangle_props = 1;
} else if (ARGS.mangle_props === "unquoted") {
ARGS.mangle_props = 2;
}
var OUTPUT_OPTIONS = {
beautify : BEAUTIFY ? true : false,
max_line_len : 32000,
preamble : ARGS.preamble || null,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0,
var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var files = {};
var options = {
compress: false,
mangle: false
};
if (ARGS.mangle_props == 2) {
OUTPUT_OPTIONS.keep_quoted_props = true;
if (COMPRESS && !("properties" in COMPRESS))
COMPRESS.properties = false;
program.version(info.name + " " + info.version);
program.parseArgv = program.parse;
program.parse = undefined;
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast;
else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() {
var text = [];
var options = UglifyJS.default_options();
for (var option in options) {
text.push("--" + (option == "output" ? "beautify" : option == "sourceMap" ? "source-map" : option) + " options:");
text.push(format_object(options[option]));
text.push("");
}
if (ARGS.support_ie8 === true && ARGS.screw_ie8 !== true) {
screw_ie8 = false;
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("-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("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.")
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages.");
program.option("--warn", "Print warning messages.");
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
program.arguments("[files...]").parseArgv(process.argv);
if (program.configFile) {
options = JSON.parse(read_file(program.configFile));
}
if (COMPRESS) COMPRESS.screw_ie8 = screw_ie8;
if (MANGLE) MANGLE.screw_ie8 = screw_ie8;
OUTPUT_OPTIONS.screw_ie8 = screw_ie8;
if (ARGS.keep_fnames) {
if (COMPRESS) COMPRESS.keep_fnames = true;
if (MANGLE) MANGLE.keep_fnames = true;
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
fatal("ERROR: cannot write source map to STDOUT");
}
if (ARGS.wrap_iife) {
if (COMPRESS) COMPRESS.negate_iife = false;
OUTPUT_OPTIONS.wrap_iife = true;
[
"compress",
"ie8",
"mangle",
"sourceMap",
"toplevel",
"wrap"
].forEach(function(name) {
if (name in program) {
options[name] = program[name];
}
if (BEAUTIFY)
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
if (ARGS.comments === "") {
OUTPUT_OPTIONS.comments = "some";
});
if ("ecma" in program) {
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
options.ecma = program.ecma | 0;
}
if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) {
options.output.beautify = true;
}
}
if (program.comments) {
if (typeof options.output != "object") options.output = {};
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
}
if (program.define) {
if (typeof options.compress != "object") options.compress = {};
if (typeof options.compress.global_defs != "object") options.compress.global_defs = {};
for (var expr in program.define) {
options.compress.global_defs[expr] = program.define[expr];
}
}
if (program.keepFnames) {
options.keep_fnames = true;
}
if (program.mangleProps) {
if (program.mangleProps.domprops) {
delete program.mangleProps.domprops;
} else {
OUTPUT_OPTIONS.comments = ARGS.comments;
if (typeof program.mangleProps != "object") program.mangleProps = {};
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS._push_uniq(program.mangleProps.reserved, name);
});
}
var files = ARGS._.slice();
if (process.platform === "win32")
files = UglifyJS.simple_glob(files);
if (ARGS.self) {
if (files.length > 0) {
if (typeof options.mangle != "object") options.mangle = {};
options.mangle.properties = program.mangleProps;
}
if (program.nameCache) {
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
}
if (program.output == "ast") {
options.output = {
ast: true,
code: false
};
}
if (program.parse) {
if (!program.parse.acorn && !program.parse.spidermonkey) {
options.parse = program.parse;
} else if (program.sourceMap && program.sourceMap.content == "inline") {
fatal("ERROR: inline source map only works with built-in parser");
}
}
var convert_path = function(name) {
return name;
};
if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
convert_path = function() {
var base = program.sourceMap.base;
delete options.sourceMap.base;
return function(name) {
return path.relative(base, name);
};
}();
}
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (program.self) {
if (program.args.length) {
print_error("WARN: Ignoring input files since --self was passed");
}
files = UglifyJS.FILES;
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
}
var ORIG_MAP = ARGS.in_source_map;
if (ORIG_MAP && ORIG_MAP != "inline") {
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
if (files.length == 0) {
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
files = [ ORIG_MAP.file ];
}
}
if (files.length == 0) {
files = [ "-" ];
}
if (ORIG_MAP == "inline") {
if (files.length > 1) {
print_error("ERROR: Inline source map only works with singular input");
process.exit(1);
}
if (ARGS.acorn || ARGS.spidermonkey) {
print_error("ERROR: Inline source map only works with built-in parser");
process.exit(1);
}
}
if (files.indexOf("-") >= 0 && ARGS.source_map) {
print_error("ERROR: Source map doesn't work with input from STDIN");
process.exit(1);
}
if (files.filter(function(el){ return el == "-" }).length > 1) {
print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
process.exit(1);
}
var STATS = {};
var TOPLEVEL = null;
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
var SOURCES_CONTENT = {};
async.eachLimit(files, 1, function (file, cb) {
read_whole_file(file, function (err, code) {
if (err) {
print_error("ERROR: can't read file: " + file);
process.exit(1);
}
if (ORIG_MAP == "inline") {
ORIG_MAP = read_source_map(code);
}
if (ARGS.p != null) {
if (P_RELATIVE) {
file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/');
if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else if (program.args.length) {
simple_glob(program.args).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else {
var p = parseInt(ARGS.p, 10);
if (!isNaN(p)) {
file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/");
}
}
}
SOURCES_CONTENT[file] = code;
time_it("parse", function(){
if (ARGS.spidermonkey) {
var program = JSON.parse(code);
if (!TOPLEVEL) TOPLEVEL = program;
else TOPLEVEL.body = TOPLEVEL.body.concat(program.body);
}
else if (ARGS.acorn) {
TOPLEVEL = acorn.parse(code, {
locations : true,
sourceFile : file,
program : TOPLEVEL
var chunks = [];
process.stdin.setEncoding("utf8");
process.stdin.on("data", function(chunk) {
chunks.push(chunk);
}).on("end", function() {
files = [ chunks.join("") ];
run();
});
process.stdin.resume();
}
else {
function convert_ast(fn) {
return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
}
function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
print_error("WARN: " + msg);
};
if (program.timings) options.timings = true;
try {
TOPLEVEL = UglifyJS.parse(code, {
filename : file,
toplevel : TOPLEVEL,
expression : ARGS.expr,
bare_returns : ARGS.bare_returns,
if (program.parse) {
if (program.parse.acorn) {
files = convert_ast(function(toplevel, name) {
return require("acorn").parse(files[name], {
locations: true,
program: toplevel,
sourceFile: name
});
});
} else if (program.parse.spidermonkey) {
files = convert_ast(function(toplevel, name) {
var obj = JSON.parse(files[name]);
if (!toplevel) return obj;
toplevel.body = toplevel.body.concat(obj.body);
return toplevel;
});
} catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
var col = ex.col;
var line = code.split(/\r?\n/)[ex.line - (col ? 1 : 2)];
if (line) {
if (col > 40) {
line = line.slice(col - 40);
col = 40;
}
if (col) {
}
} catch (ex) {
fatal(ex);
}
var result = UglifyJS.minify(files, options);
if (result.error) {
var ex = result.error;
if (ex.name == "SyntaxError") {
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
var col = ex.col;
var lines = files[ex.filename].split(/\r?\n/);
var line = lines[ex.line - 1];
if (!line && !col) {
line = lines[ex.line - 2];
col = line.length;
}
if (line) {
var limit = 70;
if (col > limit) {
line = line.slice(col - limit);
col = limit;
}
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} else {
print_error(line.slice(-40));
print_error(line.slice(-40).replace(/\S/g, " ") + "^");
}
}
print_error(ex.stack);
process.exit(1);
}
throw ex;
}
};
});
cb();
});
}, function () {
var OUTPUT_FILE = ARGS.o;
var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
root: ARGS.source_map_root || ORIG_MAP && ORIG_MAP.sourceRoot,
orig: ORIG_MAP,
}) : null;
OUTPUT_OPTIONS.source_map = SOURCE_MAP;
try {
var output = UglifyJS.OutputStream(OUTPUT_OPTIONS);
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) {
print_error(ex.message);
if (ex.defs) {
print_error("Supported options:");
print_error(sys.inspect(ex.defs));
process.exit(1);
print_error(format_object(ex.defs));
}
}
if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
fatal(ex);
} else if (program.output == "ast") {
print(JSON.stringify(result.ast, function(key, value) {
if (skip_key(key)) return;
if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return;
if (value instanceof UglifyJS.AST_Node) {
var result = {
_class: "AST_" + value.TYPE
};
value.CTOR.PROPS.forEach(function(prop) {
result[prop] = value[prop];
});
if (ARGS.wrap != null) {
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
return result;
}
return value;
}, 2));
} else if (program.output == "spidermonkey") {
print(JSON.stringify(UglifyJS.minify(result.code, {
compress: false,
mangle: false,
output: {
ast: true,
code: false
}
}).ast.to_mozilla_ast(), null, 2));
} else if (program.output) {
fs.writeFileSync(program.output, result.code);
if (result.map) {
fs.writeFileSync(program.output + ".map", result.map);
}
} else {
print(result.code);
}
if (program.nameCache) {
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
}
if (result.timings) for (var phase in result.timings) {
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
}
}
if (ARGS.enclose != null) {
var arg_parameter_list = ARGS.enclose;
if (arg_parameter_list === true) {
arg_parameter_list = [];
}
else if (!(arg_parameter_list instanceof Array)) {
arg_parameter_list = [arg_parameter_list];
}
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
}
if (ARGS.mangle_props || ARGS.name_cache) (function(){
var reserved = RESERVED ? RESERVED.props : null;
var cache = readNameCache("props");
var regex;
try {
regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null;
} catch (e) {
print_error("ERROR: Invalid --mangle-regex: " + e.message);
function fatal(message) {
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:")
print_error(message);
process.exit(1);
}
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
reserved : reserved,
cache : cache,
only_cache : !ARGS.mangle_props,
regex : regex,
ignore_quoted : ARGS.mangle_props == 2,
debug : typeof ARGS.mangle_props_debug === "undefined" ? false : ARGS.mangle_props_debug
});
writeNameCache("props", cache);
})();
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint
var TL_CACHE = readNameCache("vars");
if (MANGLE) MANGLE.cache = TL_CACHE;
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE });
if (ARGS.lint) {
TOPLEVEL.scope_warnings();
// A file glob function that only supports "*" and "?" wildcards in the basename.
// Example: "foo/bar/*baz??.*.js"
// Argument `glob` may be a string or an array of strings.
// Returns an array of strings. Garbage in, garbage out.
function simple_glob(glob) {
if (Array.isArray(glob)) {
return [].concat.apply([], glob.map(simple_glob));
}
});
}
if (COMPRESS) {
time_it("squeeze", function(){
TOPLEVEL = compressor.compress(TOPLEVEL);
});
}
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE });
if (MANGLE && !TL_CACHE) {
TOPLEVEL.compute_char_frequency(MANGLE);
}
});
}
if (MANGLE) time_it("mangle", function(){
TOPLEVEL.mangle_names(MANGLE);
});
writeNameCache("vars", TL_CACHE);
if (ARGS.source_map_include_sources) {
for (var file in SOURCES_CONTENT) {
if (SOURCES_CONTENT.hasOwnProperty(file)) {
SOURCE_MAP.get().setSourceContent(file, SOURCES_CONTENT[file]);
}
}
}
if (ARGS.dump_spidermonkey_ast) {
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2));
} else {
time_it("generate", function(){
TOPLEVEL.print(output);
});
output = output.get();
if (SOURCE_MAP) {
if (ARGS.source_map_inline) {
var base64_string = new Buffer(SOURCE_MAP.toString()).toString('base64');
output += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + base64_string;
} else {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
var source_map_url = ARGS.source_map_url || (
P_RELATIVE
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
: ARGS.source_map
);
output += "\n//# sourceMappingURL=" + source_map_url;
}
}
if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else {
print(output);
}
}
if (ARGS.stats) {
print_error(UglifyJS.string_template("Timing information (compressed {count} files):", {
count: files.length
}));
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
print_error(UglifyJS.string_template("- {name}: {time}s", {
name: i,
time: (STATS[i] / 1000).toFixed(3)
}));
}
}
});
/* -----[ functions ]----- */
function normalize(o) {
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
o[i.replace(/-/g, "_")] = o[i];
delete o[i];
}
}
function getOptions(flag, constants) {
var x = ARGS[flag];
if (x == null || x === false) return null;
var ret = {};
if (x !== "") {
if (Array.isArray(x)) x = x.map(function (v) { return "(" + v + ")"; }).join(", ");
var ast;
if (glob.match(/\*|\?/)) {
var dir = path.dirname(glob);
try {
ast = UglifyJS.parse(x, { expression: true });
var entries = fs.readdirSync(dir);
} catch (ex) {}
if (entries) {
var pattern = "^" + path.basename(glob)
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
.replace(/\*/g, "[^/\\\\]*")
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.filter(function(name) {
return rx.test(name);
}).map(function(name) {
return path.join(dir, name);
});
if (results.length) return results;
}
}
return [ glob ];
}
function read_file(path, default_value) {
try {
return fs.readFileSync(path, "utf8");
} catch (ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Error parsing arguments for flag `" + flag + "': " + x);
process.exit(1);
if (ex.code == "ENOENT" && default_value != null) return default_value;
fatal(ex);
}
}
ast.walk(new UglifyJS.TreeWalker(function(node){
if (node instanceof UglifyJS.AST_Seq) return; // descend
function parse_js(flag, constants) {
return function(value, options) {
options = options || {};
try {
UglifyJS.minify(value, {
parse: {
expression: true
},
compress: false,
mangle: false,
output: {
ast: true,
code: false
}
}).ast.walk(new UglifyJS.TreeWalker(function(node) {
if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string().replace(/-/g, "_");
var name = node.left.print_to_string();
var value = node.right;
if (constants)
value = new Function("return (" + value.print_to_string() + ")")();
ret[name] = value;
return true; // no descend
}
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) {
var name = node.print_to_string().replace(/-/g, "_");
ret[name] = true;
return true; // no descend
}
print_error(node.TYPE)
print_error("Error parsing arguments for flag `" + flag + "': " + x);
process.exit(1);
}));
}
return ret;
}
function read_whole_file(filename, cb) {
if (filename == "-") {
var chunks = [];
process.stdin.setEncoding('utf-8');
process.stdin.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function () {
cb(null, chunks.join(""));
});
process.openStdin();
if (!constants) {
options[name] = value;
} else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string);
} else {
fs.readFile(filename, "utf-8", cb);
options[name] = to_string(value);
}
return true;
}
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
var name = node.print_to_string();
options[name] = true;
return true;
}
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
function to_string(value) {
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({
quote_keys: true
});
}
}));
} catch(ex) {
options[value] = null;
}
return options;
}
}
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
print_error("WARN: inline source map not found");
return null;
function parse_source_map() {
var parse = parse_js("sourceMap", true);
return function(value, options) {
var hasContent = options && "content" in options;
var settings = parse(value, options);
if (!hasContent && settings.content && settings.content != "inline") {
print_error("INFO: Using input source map: " + settings.content);
settings.content = read_file(settings.content, settings.content);
}
return settings;
}
return JSON.parse(new Buffer(match[2], "base64"));
}
function time_it(name, cont) {
var t1 = new Date().getTime();
var ret = cont();
if (ARGS.stats) {
var spent = new Date().getTime() - t1;
if (STATS[name]) STATS[name] += spent;
else STATS[name] = spent;
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
}
return ret;
function format_object(obj) {
var lines = [];
var padding = "";
Object.keys(obj).map(function(name) {
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
return [ name, JSON.stringify(obj[name]) ];
}).forEach(function(tokens) {
lines.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
});
return lines.join("\n");
}
function print_error(msg) {
console.error("%s", msg);
process.stderr.write(msg);
process.stderr.write("\n");
}
function print(txt) {
console.log("%s", txt);
process.stdout.write(txt);
process.stdout.write("\n");
}

View File

@@ -91,9 +91,20 @@ var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos
}, null);
var AST_Node = DEFNODE("Node", "start end", {
clone: function() {
_clone: function(deep) {
if (deep) {
var self = this.clone();
return self.transform(new TreeTransformer(function(node) {
if (node !== self) {
return node.clone(true);
}
}));
}
return new this.CTOR(this);
},
clone: function(deep) {
return this._clone(deep);
},
$documentation: "Base class of all AST nodes",
$propdoc: {
start: "[AST_Token] The first token of this node",
@@ -146,7 +157,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Statement) {
if (body instanceof AST_Node) {
body._walk(visitor);
}
else for (var i = 0, len = body.length; i < len; i++) {
@@ -171,21 +182,13 @@ var AST_BlockStatement = DEFNODE("BlockStatement", null, {
}, AST_Block);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)",
_walk: function(visitor) {
return visitor._visit(this);
}
$documentation: "The empty statement (empty block or simply a semicolon)"
}, AST_Statement);
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
$propdoc: {
body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.body._walk(visitor);
});
}
}, AST_Statement);
@@ -199,6 +202,21 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
this.label._walk(visitor);
this.body._walk(visitor);
});
},
clone: function(deep) {
var node = this._clone(deep);
if (deep) {
var label = node.label;
var def = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === def) {
node.label.thedef = label;
label.references.push(node);
}
}));
}
return node;
}
}, AST_StatementWithBody);
@@ -266,6 +284,10 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", {
}
}, AST_IterationStatement);
var AST_ForOf = DEFNODE("ForOf", null, {
$documentation: "A `for ... of` statement",
}, AST_ForIn);
var AST_With = DEFNODE("With", "expression", {
$documentation: "A `with` statement",
$propdoc: {
@@ -293,6 +315,13 @@ 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 () {
var self = this;
while (self.is_block_scope() && self.parent_scope) {
self = self.parent_scope;
}
return self;
}
}, AST_Block);
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
@@ -300,74 +329,51 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$propdoc: {
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
},
wrap_enclose: function(arg_parameter_pairs) {
var self = this;
var args = [];
var parameters = [];
arg_parameter_pairs.forEach(function(pair) {
var splitAt = pair.lastIndexOf(":");
args.push(pair.substr(0, splitAt));
parameters.push(pair.substr(splitAt + 1));
});
var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
wrap_commonjs: function(name) {
var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(self.body);
}
}));
return wrapped_tl;
},
wrap_commonjs: function(name, export_all) {
var self = this;
var to_export = [];
if (export_all) {
self.figure_out_scope();
self.walk(new TreeWalker(function(node){
if (node instanceof AST_SymbolDeclaration && node.definition().global) {
if (!find_if(function(n){ return n.name == node.name }, to_export))
to_export.push(node);
}
}));
}
var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))";
wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
if (node instanceof AST_Directive) {
switch (node.value) {
case "$ORIG":
return MAP.splice(self.body);
case "$EXPORTS":
var body = [];
to_export.forEach(function(sym){
body.push(new AST_SimpleStatement({
body: new AST_Assign({
left: new AST_Sub({
expression: new AST_SymbolRef({ name: "exports" }),
property: new AST_String({ value: sym.name }),
}),
operator: "=",
right: new AST_SymbolRef(sym),
}),
}));
});
return MAP.splice(body);
}
}
}));
return wrapped_tl;
}
}, AST_Scope);
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
var AST_Expansion = DEFNODE("Expansion", "expression", {
$documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
$propdoc: {
expression: "[AST_Node] the thing to be expanded"
},
_walk: function(visitor) {
var self = this;
return visitor._visit(this, function(){
self.expression.walk(visitor);
});
}
});
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator async", {
$documentation: "Base class for functions",
$propdoc: {
name: "[AST_SymbolDeclaration?] the name of this function",
argnames: "[AST_SymbolFunarg*] array of function arguments",
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
is_generator: "[boolean] is this a generator method",
async: "[boolean] is this method async",
},
args_as_names: function () {
var out = [];
for (var i = 0; i < this.argnames.length; i++) {
if (this.argnames[i] instanceof AST_Destructuring) {
out = out.concat(this.argnames[i].all_symbols());
} else {
out.push(this.argnames[i]);
}
}
return out;
},
_walk: function(visitor) {
return visitor._visit(this, function(){
@@ -389,10 +395,78 @@ var AST_Function = DEFNODE("Function", null, {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Arrow = DEFNODE("Arrow", null, {
$documentation: "An ES6 Arrow function ((a) => b)"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
$documentation: "A function definition"
}, AST_Lambda);
/* -----[ DESTRUCTURING ]----- */
var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
$propdoc: {
"names": "[AST_Node*] Array of properties or elements",
"is_array": "[Boolean] Whether the destructuring represents an object or array"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.names.forEach(function(name){
name._walk(visitor);
});
});
},
all_symbols: function() {
var out = [];
this.walk(new TreeWalker(function (node) {
if (node instanceof AST_Symbol) {
out.push(node);
}
if (node instanceof AST_Expansion) {
out.push(node.expression);
}
}));
return out;
}
});
var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", {
$documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
$propdoc: {
template_string: "[AST_TemplateString] The template string",
prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
},
_walk: function(visitor) {
this.prefix._walk(visitor);
this.template_string._walk(visitor);
}
})
var AST_TemplateString = DEFNODE("TemplateString", "segments", {
$documentation: "A template string literal",
$propdoc: {
segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.segments.forEach(function(seg, i){
if (i % 2 !== 0) {
seg._walk(visitor);
}
});
});
}
});
var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", {
$documentation: "A segment of a template string literal",
$propdoc: {
value: "Content of the segment",
raw: "Raw content of the segment"
}
});
/* -----[ JUMPS ]----- */
var AST_Jump = DEFNODE("Jump", null, {
@@ -512,7 +586,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
var AST_Catch = DEFNODE("Catch", "argname", {
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
$propdoc: {
argname: "[AST_SymbolCatch] symbol for the exception"
argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
@@ -547,14 +621,83 @@ var AST_Var = DEFNODE("Var", null, {
$documentation: "A `var` statement"
}, AST_Definitions);
var AST_Let = DEFNODE("Let", null, {
$documentation: "A `let` statement"
}, AST_Definitions);
var AST_Const = DEFNODE("Const", null, {
$documentation: "A `const` statement"
}, AST_Definitions);
var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
$documentation: "The part of the export/import statement that declare names from a module.",
$propdoc: {
foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)",
name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module."
},
_walk: function (visitor) {
return visitor._visit(this, function() {
this.foreign_name._walk(visitor);
this.name._walk(visitor);
});
}
})
var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
$documentation: "An `import` statement",
$propdoc: {
imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
imported_names: "[AST_NameMapping*] The names of non-default imported variables",
module_name: "[AST_String] String literal describing where this module came from",
},
_walk: function(visitor) {
return visitor._visit(this, function() {
if (this.imported_name) {
this.imported_name._walk(visitor);
}
if (this.imported_names) {
this.imported_names.forEach(function(name_import) {
name_import._walk(visitor);
});
}
this.module_name._walk(visitor);
});
}
});
var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
$documentation: "An `export` statement",
$propdoc: {
exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
exported_value: "[AST_Node?] An exported value",
exported_names: "[AST_NameMapping*?] List of exported names",
module_name: "[AST_String?] Name of the file to load exports from",
is_default: "[Boolean] Whether this is the default exported value of this module"
},
_walk: function (visitor) {
visitor._visit(this, function () {
if (this.exported_definition) {
this.exported_definition._walk(visitor);
}
if (this.exported_value) {
this.exported_value._walk(visitor);
}
if (this.exported_names) {
this.exported_names.forEach(function(name_export) {
name_export._walk(visitor);
});
}
if (this.module_name) {
this.module_name._walk(visitor);
}
});
}
}, AST_Statement);
var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
name: "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
@@ -575,11 +718,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
this.expression._walk(visitor);
});
}
});
@@ -588,68 +731,16 @@ var AST_New = DEFNODE("New", null, {
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
}, AST_Call);
var AST_Seq = DEFNODE("Seq", "car cdr", {
$documentation: "A sequence expression (two comma-separated expressions)",
var AST_Sequence = DEFNODE("Sequence", "expressions", {
$documentation: "A sequence expression (comma-separated expressions)",
$propdoc: {
car: "[AST_Node] first element in sequence",
cdr: "[AST_Node] second element in sequence"
},
$cons: function(x, y) {
var seq = new AST_Seq(x);
seq.car = x;
seq.cdr = y;
return seq;
},
$from_array: function(array) {
if (array.length == 0) return null;
if (array.length == 1) return array[0].clone();
var list = null;
for (var i = array.length; --i >= 0;) {
list = AST_Seq.cons(array[i], list);
}
var p = list;
while (p) {
if (p.cdr && !p.cdr.cdr) {
p.cdr = p.cdr.car;
break;
}
p = p.cdr;
}
return list;
},
to_array: function() {
var p = this, a = [];
while (p) {
a.push(p.car);
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
a.push(p.cdr);
break;
}
p = p.cdr;
}
return a;
},
add: function(node) {
var p = this;
while (p) {
if (!(p.cdr instanceof AST_Seq)) {
var cell = AST_Seq.cons(p.cdr, node);
return p.cdr = cell;
}
p = p.cdr;
}
},
len: function() {
if (this.cdr instanceof AST_Seq) {
return this.cdr.len() + 1;
} else {
return 2;
}
expressions: "[AST_Node*] array of expressions (at least two)"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.car._walk(visitor);
if (this.cdr) this.cdr._walk(visitor);
this.expressions.forEach(function(node) {
node._walk(visitor);
});
});
}
});
@@ -702,7 +793,7 @@ var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
$documentation: "Unary postfix expression, i.e. `i++`"
}, AST_Unary);
var AST_Binary = DEFNODE("Binary", "left operator right", {
var AST_Binary = DEFNODE("Binary", "operator left right", {
$documentation: "Binary expression, i.e. `a + b`",
$propdoc: {
left: "[AST_Node] left-hand side expression",
@@ -737,6 +828,10 @@ var AST_Assign = DEFNODE("Assign", null, {
$documentation: "An assignment expression — `a = b + 5`",
}, AST_Binary);
var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
$documentation: "A default assignment expression like in `(a = 3) => a`"
}, AST_Binary);
/* -----[ LITERALS ]----- */
var AST_Array = DEFNODE("Array", "elements", {
@@ -772,11 +867,13 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
key: "[string|AST_Node] the property name converted to a string for ObjectKeyVal. For setters, getters and computed property this is an arbitrary AST_Node",
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.key instanceof AST_Node)
this.key._walk(visitor);
this.value._walk(visitor);
});
}
@@ -789,41 +886,94 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
}
}, AST_ObjectProperty);
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] whether this is a static setter (classes only)"
},
$documentation: "An object setter property",
}, AST_ObjectProperty);
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] whether this is a static getter (classes only)"
},
$documentation: "An object getter property",
}, AST_ObjectProperty);
var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator async", {
$propdoc: {
quote: "[string|undefined] the original quote character, if any",
static: "[boolean] is this method static (classes only)",
is_generator: "[boolean] is this a generator method",
async: "[boolean] is this method async",
},
$documentation: "An ES6 concise method inside an object or class"
}, AST_ObjectProperty);
var AST_Class = DEFNODE("Class", "name extends properties", {
$propdoc: {
name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
extends: "[AST_Node]? optional parent class",
properties: "[AST_ObjectProperty*] array of properties"
},
$documentation: "An ES6 class",
_walk: function(visitor) {
return visitor._visit(this, function(){
if (this.name) {
this.name._walk(visitor);
}
if (this.extends) {
this.extends._walk(visitor);
}
this.properties.forEach(function(prop){
prop._walk(visitor);
});
});
},
}, AST_Scope);
var AST_DefClass = DEFNODE("DefClass", null, {
$documentation: "A class definition",
}, AST_Class);
var AST_ClassExpression = DEFNODE("ClassExpression", null, {
$documentation: "A class expression."
}, AST_Class);
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
$propdoc: {
name: "[string] name of this symbol",
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
thedef: "[SymbolDef/S] the definition of this symbol"
},
$documentation: "Base class for all symbols",
$documentation: "Base class for all symbols"
});
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
$documentation: "The name of a property accessor (setter/getter function)"
}, AST_Symbol);
var AST_NewTarget = DEFNODE("NewTarget", null, {
$documentation: "A reference to new.target"
});
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
$propdoc: {
init: "[AST_Node*/S] array of initializers for this declaration."
}
}, AST_Symbol);
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable",
}, AST_SymbolDeclaration);
var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, {
$documentation: "Base class for block-scoped declaration symbols"
}, AST_SymbolDeclaration);
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
$documentation: "A constant declaration"
}, AST_SymbolDeclaration);
}, AST_SymbolBlockDeclaration);
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
$documentation: "A block-scoped `let` declaration"
}, AST_SymbolBlockDeclaration);
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
$documentation: "Symbol naming a function argument",
@@ -833,13 +983,33 @@ var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
$documentation: "Symbol defining a function",
}, AST_SymbolDeclaration);
var AST_SymbolMethod = DEFNODE("SymbolMethod", null, {
$documentation: "Symbol in an object defining a method",
}, AST_Symbol);
var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
$documentation: "Symbol naming a function expression",
}, AST_SymbolDeclaration);
var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
$documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
}, AST_SymbolBlockDeclaration);
var AST_SymbolClass = DEFNODE("SymbolClass", null, {
$documentation: "Symbol naming a class's name. Lexically scoped to the class."
}, AST_SymbolDeclaration);
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
$documentation: "Symbol naming the exception in catch",
}, AST_SymbolDeclaration);
}, AST_SymbolBlockDeclaration);
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
$documentation: "Symbol referring to an imported name",
}, AST_SymbolBlockDeclaration);
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
$documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
}, AST_Symbol);
var AST_Label = DEFNODE("Label", "references", {
$documentation: "Symbol naming a label (declaration)",
@@ -856,6 +1026,14 @@ var AST_SymbolRef = DEFNODE("SymbolRef", null, {
$documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol);
var AST_SymbolExport = DEFNODE("SymbolExport", null, {
$documentation: "Symbol referring to a name to export",
}, AST_SymbolRef);
var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, {
$documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes",
}, AST_Symbol);
var AST_LabelRef = DEFNODE("LabelRef", null, {
$documentation: "Reference to a label symbol",
}, AST_Symbol);
@@ -864,6 +1042,10 @@ var AST_This = DEFNODE("This", null, {
$documentation: "The `this` symbol",
}, AST_Symbol);
var AST_Super = DEFNODE("Super", null, {
$documentation: "The `super` symbol",
}, AST_Symbol);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
getValue: function() {
@@ -937,6 +1119,31 @@ var AST_True = DEFNODE("True", null, {
value: true
}, AST_Boolean);
var AST_Await = DEFNODE("Await", "expression", {
$documentation: "An `await` statement",
$propdoc: {
expression: "[AST_Node] the mandatory expression being awaited",
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
});
}
});
var AST_Yield = DEFNODE("Yield", "expression is_star", {
$documentation: "A `yield` statement",
$propdoc: {
expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false",
is_star: "[Boolean] Whether this is a yield or yield* statement"
},
_walk: function(visitor) {
return visitor._visit(this, this.expression && function(){
this.expression._walk(visitor);
});
}
});
/* -----[ TreeWalker ]----- */
function TreeWalker(callback) {
@@ -962,14 +1169,19 @@ TreeWalker.prototype = {
push: function(node) {
if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive) {
this.directives[node.value] = this.directives[node.value] ? "up" : true;
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
} else if (node instanceof AST_Class) {
this.directives = Object.create(this.directives);
if (!this.directives["use strict"]) {
this.directives["use strict"] = node;
}
}
this.stack.push(node);
},
pop: function(node) {
this.stack.pop();
if (node instanceof AST_Lambda) {
if (node instanceof AST_Lambda || node instanceof AST_Class) {
this.directives = Object.getPrototypeOf(this.directives);
}
},
@@ -987,11 +1199,11 @@ TreeWalker.prototype = {
var dir = this.directives[type];
if (dir) return dir;
var node = this.stack[this.stack.length - 1];
if (node instanceof AST_Scope) {
if (node instanceof AST_Scope && node.body) {
for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i];
if (!(st instanceof AST_Directive)) break;
if (st.value == type) return true;
if (st.value == type) return st;
}
}
},
@@ -1013,16 +1225,16 @@ TreeWalker.prototype = {
self = p;
}
},
loopcontrol_target: function(label) {
loopcontrol_target: function(node) {
var stack = this.stack;
if (label) for (var i = stack.length; --i >= 0;) {
if (node.label) for (var i = stack.length; --i >= 0;) {
var x = stack[i];
if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
if (x instanceof AST_LabeledStatement && x.label.name == node.label.name)
return x.body;
}
} else for (var i = stack.length; --i >= 0;) {
var x = stack[i];
if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
if (x instanceof AST_IterationStatement
|| node instanceof AST_Break && x instanceof AST_Switch)
return x;
}
}

File diff suppressed because it is too large Load Diff

215
lib/minify.js Normal file
View File

@@ -0,0 +1,215 @@
"use strict";
var to_ascii = typeof atob == "undefined" ? function(b64) {
return new Buffer(b64, "base64").toString();
} : atob;
var to_base64 = typeof btoa == "undefined" ? function(str) {
return new Buffer(str).toString("base64");
} : btoa;
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
AST_Node.warn("inline source map not found");
return null;
}
return to_ascii(match[2]);
}
function set_shorthand(name, options, keys) {
if (options[name]) {
keys.forEach(function(key) {
if (options[key]) {
if (typeof options[key] != "object") options[key] = {};
if (!(name in options[key])) options[key][name] = options[name];
}
});
}
}
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)) {
cache.props = Dictionary.fromObject(cache.props);
}
}
function to_json(cache) {
return {
cname: cache.cname,
props: cache.props.toObject()
};
}
function minify(files, options) {
var warn_function = AST_Node.warn_function;
try {
options = defaults(options, {
compress: {},
ecma: undefined,
ie8: false,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
sourceMap: false,
timings: false,
toplevel: false,
warnings: false,
wrap: false,
}, true);
var timings = options.timings && {
start: Date.now()
};
set_shorthand("ecma", options, [ "parse", "compress", "output" ]);
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
if (options.mangle) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
eval: false,
ie8: false,
keep_classnames: false,
keep_fnames: false,
properties: false,
reserved: [],
safari10: false,
toplevel: false,
}, true);
if (options.nameCache && options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
options.mangle.properties = {};
}
if (!("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {};
}
}
init_cache(options.mangle.cache);
init_cache(options.mangle.properties.cache);
}
if (options.sourceMap) {
options.sourceMap = defaults(options.sourceMap, {
content: null,
filename: null,
includeSources: false,
root: null,
url: null,
}, true);
}
var warnings = [];
if (options.warnings && !AST_Node.warn_function) {
AST_Node.warn_function = function(warning) {
warnings.push(warning);
};
}
if (timings) timings.parse = Date.now();
var toplevel;
if (files instanceof AST_Toplevel) {
toplevel = files;
} else {
if (typeof files == "string") {
files = [ files ];
}
options.parse = options.parse || {};
options.parse.toplevel = null;
for (var name in files) if (HOP(files, name)) {
options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse);
if (options.sourceMap && options.sourceMap.content == "inline") {
if (Object.keys(files).length > 1)
throw new Error("inline source map only works with singular input");
options.sourceMap.content = read_source_map(files[name]);
}
}
toplevel = options.parse.toplevel;
}
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.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope2 = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
base54.reset();
toplevel.compute_char_frequency(options.mangle);
toplevel.mangle_names(options.mangle);
}
if (timings) timings.properties = Date.now();
if (options.mangle && options.mangle.properties) {
toplevel = mangle_properties(toplevel, options.mangle.properties);
}
if (timings) timings.output = Date.now();
var result = {};
if (options.output.ast) {
result.ast = toplevel;
}
if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) {
if (typeof options.sourceMap.content == "string") {
options.sourceMap.content = JSON.parse(options.sourceMap.content);
}
options.output.source_map = SourceMap({
file: options.sourceMap.filename,
orig: options.sourceMap.content,
root: options.sourceMap.root
});
if (options.sourceMap.includeSources) {
if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable");
} else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]);
}
}
}
delete options.output.ast;
delete options.output.code;
var stream = OutputStream(options.output);
toplevel.print(stream);
result.code = stream.get();
if (options.sourceMap) {
result.map = options.output.source_map.toString();
if (options.sourceMap.url == "inline") {
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map);
} else if (options.sourceMap.url) {
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url;
}
}
}
if (options.nameCache && options.mangle) {
if (options.mangle.cache) options.nameCache.vars = to_json(options.mangle.cache);
if (options.mangle.properties && options.mangle.properties.cache) {
options.nameCache.props = to_json(options.mangle.properties.cache);
}
}
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),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),
total: 1e-3 * (timings.end - timings.start)
}
}
if (warnings.length) {
result.warnings = warnings;
}
return result;
} catch (ex) {
return { error: ex };
} finally {
AST_Node.warn_function = warn_function;
}
}

View File

@@ -111,23 +111,19 @@
},
Property: function(M) {
var key = M.key;
var name = key.type == "Identifier" ? key.name : key.value;
var args = {
start : my_start_token(key),
end : my_end_token(M.value),
key : name,
key : key.type == "Identifier" ? key.name : key.value,
value : from_moz(M.value)
};
switch (M.kind) {
case "init":
return new AST_ObjectKeyVal(args);
case "set":
args.value.name = from_moz(key);
return new AST_ObjectSetter(args);
case "get":
args.value.name = from_moz(key);
return new AST_ObjectGetter(args);
}
if (M.kind == "init") return new AST_ObjectKeyVal(args);
args.key = new AST_SymbolMethod({
name: args.key
});
args.value = new AST_Accessor(args.value);
if (M.kind == "get") return new AST_ObjectGetter(args);
if (M.kind == "set") return new AST_ObjectSetter(args);
},
ArrayExpression: function(M) {
return new AST_Array({
@@ -149,7 +145,11 @@
});
},
SequenceExpression: function(M) {
return AST_Seq.from_array(M.expressions.map(from_moz));
return new AST_Sequence({
start : my_start_token(M),
end : my_end_token(M),
expressions: M.expressions.map(from_moz)
});
},
MemberExpression: function(M) {
return new (M.computed ? AST_Sub : AST_Dot)({
@@ -256,10 +256,7 @@
map("CallExpression", AST_Call, "callee>expression, arguments@args");
def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
return {
type: "Program",
body: M.body.map(to_moz)
};
return to_moz_scope("Program", M);
});
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
@@ -267,7 +264,7 @@
type: "FunctionDeclaration",
id: to_moz(M.name),
params: M.argnames.map(to_moz),
body: to_moz_block(M)
body: to_moz_scope("BlockStatement", M)
}
});
@@ -276,7 +273,7 @@
type: "FunctionExpression",
id: to_moz(M.name),
params: M.argnames.map(to_moz),
body: to_moz_block(M)
body: to_moz_scope("BlockStatement", M)
}
});
@@ -332,10 +329,10 @@
};
});
def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) {
def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
return {
type: "SequenceExpression",
expressions: M.to_array().map(to_moz)
expressions: M.expressions.map(to_moz)
};
});
@@ -382,11 +379,10 @@
});
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
var key = (
is_identifier(M.key)
? {type: "Identifier", name: M.key}
: {type: "Literal", value: M.key}
);
var key = {
type: "Literal",
value: M.key instanceof AST_SymbolMethod ? M.key.name : M.key
};
var kind;
if (M instanceof AST_ObjectKeyVal) {
kind = "init";
@@ -547,8 +543,8 @@
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
exports, my_start_token, my_end_token, from_moz
);
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
to_moz, to_moz_block
me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")(
to_moz, to_moz_block, to_moz_scope
);
MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz);
@@ -606,4 +602,14 @@
};
};
function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
}
return {
type: type,
body: body
};
};
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -43,11 +43,37 @@
"use strict";
function find_builtins() {
var a = [];
function find_builtins(reserved) {
// Compatibility fix for some standard defined globals not defined on every js environment
var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"];
var objects = {};
var global_ref = typeof global === "object" ? global : self;
new_globals.forEach(function (new_global) {
objects[new_global] = global_ref[new_global] || new Function();
});
// NaN will be included due to Number.NaN
[
"null",
"true",
"false",
"Infinity",
"-Infinity",
"undefined",
].forEach(add);
[ Object, Array, Function, Number,
String, Boolean, Error, Math,
Date, RegExp
Date, RegExp, objects.Symbol, ArrayBuffer,
DataView, decodeURI, decodeURIComponent,
encodeURI, encodeURIComponent, eval, EvalError,
Float32Array, Float64Array, Int8Array, Int16Array,
Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat,
parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError,
objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array,
Uint8ClampedArray, Uint16Array, Uint32Array, URIError,
objects.WeakMap, objects.WeakSet
].forEach(function(ctor){
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
@@ -55,24 +81,24 @@ function find_builtins() {
}
});
function add(name) {
push_uniq(a, name);
push_uniq(reserved, name);
}
return a;
}
function mangle_properties(ast, options) {
options = defaults(options, {
reserved : null,
builtins: false,
cache: null,
debug: false,
keep_quoted: false,
only_cache: false,
regex: null,
ignore_quoted : false,
debug : false
reserved: null,
});
var reserved = options.reserved;
if (reserved == null)
reserved = find_builtins();
if (!Array.isArray(reserved)) reserved = [];
if (!options.builtins) find_builtins(reserved);
var cache = options.cache;
if (cache == null) {
@@ -83,12 +109,12 @@ function mangle_properties(ast, options) {
}
var regex = options.regex;
var ignore_quoted = options.ignore_quoted;
var keep_quoted = options.keep_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
// the same as passing an empty string.
var debug = (options.debug !== false);
var debug = options.debug !== false;
var debug_name_suffix;
if (debug) {
debug_name_suffix = (options.debug === true ? "" : options.debug);
@@ -96,12 +122,12 @@ function mangle_properties(ast, options) {
var names_to_mangle = [];
var unmangleable = [];
var ignored = {};
var to_keep = {};
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) {
add(node.key, ignore_quoted && node.quote);
add(node.key, keep_quoted && node.quote);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above
@@ -111,14 +137,17 @@ function mangle_properties(ast, options) {
add(node.property);
}
else if (node instanceof AST_Sub) {
addStrings(node.property, ignore_quoted);
addStrings(node.property, keep_quoted);
}
else if (node instanceof AST_ConciseMethod) {
add(node.name.name);
}
}));
// step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) {
if (!(ignore_quoted && node.quote))
if (!(keep_quoted && node.quote))
node.key = mangle(node.key);
}
else if (node instanceof AST_ObjectProperty) {
@@ -129,9 +158,14 @@ function mangle_properties(ast, options) {
node.property = mangle(node.property);
}
else if (node instanceof AST_Sub) {
if (!ignore_quoted)
if (!keep_quoted)
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(
@@ -149,27 +183,26 @@ function mangle_properties(ast, options) {
// only function declarations after this line
function can_mangle(name) {
if (!is_identifier(name)) return false;
if (unmangleable.indexOf(name) >= 0) return false;
if (reserved.indexOf(name) >= 0) return false;
if (options.only_cache) {
return cache.props.has(name);
}
if (/^[0-9.]+$/.test(name)) return false;
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
return true;
}
function should_mangle(name) {
if (ignore_quoted && name in ignored) return false;
if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0;
}
function add(name, ignore) {
if (ignore) {
ignored[name] = true;
function add(name, keep) {
if (keep) {
to_keep[name] = true;
return;
}
@@ -192,19 +225,19 @@ function mangle_properties(ast, options) {
// 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) && !(ignore_quoted && debug_mangled in ignored)) {
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
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 'ignored' set
// (filled with quoted properties when ignore_quoted set). Make sure we add this
// 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) || (ignore_quoted && mangled in ignored));
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
}
cache.props.set(name, mangled);
@@ -212,17 +245,17 @@ function mangle_properties(ast, options) {
return mangled;
}
function addStrings(node, ignore) {
function addStrings(node, keep) {
var out = {};
try {
(function walk(node){
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Seq) {
walk(node.cdr);
if (node instanceof AST_Sequence) {
walk(node.expressions[node.expressions.length - 1]);
return true;
}
if (node instanceof AST_String) {
add(node.value, ignore);
add(node.value, keep);
return true;
}
if (node instanceof AST_Conditional) {
@@ -240,8 +273,9 @@ function mangle_properties(ast, options) {
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Seq) {
node.cdr = mangleStrings(node.cdr);
if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]);
}
else if (node instanceof AST_String) {
node.value = mangle(node.value);
@@ -253,5 +287,4 @@ function mangle_properties(ast, options) {
return node;
}));
}
}

View File

@@ -49,6 +49,7 @@ function SymbolDef(scope, index, orig) {
this.scope = scope;
this.references = [];
this.global = false;
this.export = false;
this.mangled_name = null;
this.undeclared = false;
this.index = index;
@@ -62,11 +63,16 @@ SymbolDef.prototype = {
if (!options) options = {};
return (this.global && !options.toplevel)
|| this.export
|| this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|| (options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun));
|| this.orig[0] instanceof AST_SymbolDefun))
|| this.orig[0] instanceof AST_SymbolMethod
|| (options.keep_classnames
&& (this.orig[0] instanceof AST_SymbolClass
|| this.orig[0] instanceof AST_SymbolDefClass));
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
@@ -75,20 +81,29 @@ SymbolDef.prototype = {
}
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
var sym = this.orig[0];
if (options.ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
var def;
if (def = this.redefined()) {
this.mangled_name = def.mangled_name || def.name;
} else
this.mangled_name = s.next_mangled(options, this);
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
}
},
redefined: function() {
return this.defun && this.defun.variables.get(this.name);
}
};
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
options = defaults(options, {
screw_ie8: true,
cache: null
cache: null,
ie8: false,
safari10: false,
});
// pass 1: setup scope chaining and handle definitions
@@ -96,19 +111,36 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var in_destructuring = null;
var for_scopes = [];
var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) {
if (node.is_block_scope()) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars();
scope.parent_scope = save_scope;
scope.init_scope_vars(save_scope);
if (!(node instanceof AST_Scope)) {
scope.uses_with = save_scope.uses_with;
scope.uses_eval = save_scope.uses_eval;
scope.directives = save_scope.directives;
}
if (options.safari10) {
if (node instanceof AST_For || node instanceof AST_ForIn) {
for_scopes.push(scope);
}
}
descend();
scope = save_scope;
return true;
}
if (node instanceof AST_Destructuring) {
in_destructuring = node; // These don't nest
descend();
in_destructuring = null;
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars();
var save_scope = node.parent_scope = scope;
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
@@ -150,16 +182,40 @@ 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.
(node.scope = defun.parent_scope).def_function(node);
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);
}
else if (node instanceof AST_SymbolClass) {
mark_export(defun.def_variable(node), 1);
}
else if (node instanceof AST_SymbolImport) {
scope.def_variable(node);
}
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);
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolLet
|| node instanceof AST_SymbolConst) {
var def = defun.def_variable(node);
def.init = tw.parent().value;
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node);
if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2);
def.destructuring = in_destructuring;
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
node.reference(options);
}
}
}
else if (node instanceof AST_SymbolCatch) {
(options.screw_ie8 ? scope : defun)
.def_variable(node);
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
@@ -170,20 +226,32 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}));
node.thedef = sym;
}
if (!(scope instanceof AST_Toplevel) && (node instanceof AST_Export || node instanceof AST_Import)) {
js_error(
node.TYPE + " statement may only appear at top level",
node.start.file,
node.start.line,
node.start.col,
node.start.pos
);
}
function mark_export(def, level) {
if (in_destructuring) {
var i = 0;
do {
level++;
} while (tw.parent(i++) !== in_destructuring);
}
var node = tw.parent(level);
def.export = node instanceof AST_Export;
}
});
self.walk(tw);
// pass 2: find back references and eval
var func = null;
var globals = self.globals = new Dictionary();
self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Lambda) {
var prev_func = func;
func = node;
descend();
func = prev_func;
return true;
}
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
@@ -195,20 +263,61 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
s.uses_eval = true;
}
}
var sym = node.scope.find_variable(name);
if (node.scope instanceof AST_Lambda && name == "arguments") {
node.scope.uses_arguments = true;
}
if (!sym) {
var sym;
if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name
|| !(sym = node.scope.find_variable(name))) {
sym = self.def_global(node);
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
sym.scope.uses_arguments = true;
}
node.thedef = sym;
node.reference(options);
return true;
}
// ensure mangling works if catch reuses a scope variable
var def;
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
var s = node.scope;
while (s) {
push_uniq(s.enclosed, def);
if (s === def.scope) break;
s = s.parent_scope;
}
}
});
self.walk(tw);
// pass 3: fix up any scoping issue with IE8
if (options.ie8) {
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) {
var name = node.name;
var refs = node.thedef.references;
var scope = node.thedef.defun;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
refs.forEach(function(ref) {
ref.thedef = def;
ref.reference(options);
});
node.thedef = def;
return true;
}
}));
}
// pass 4: add symbol definitions to loop scopes
// Safari/Webkit bug workaround - loop init let variable shadowing argument.
// https://github.com/mishoo/UglifyJS2/issues/1753
// https://bugs.webkit.org/show_bug.cgi?id=171041
if (options.safari10) {
for (var i = 0; i < for_scopes.length; i++) {
var scope = for_scopes[i];
scope.parent_scope.variables.each(function(def) {
push_uniq(scope.enclosed, def);
});
}
}
if (options.cache) {
this.cname = options.cache.cname;
}
@@ -227,28 +336,36 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(){
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
this.parent_scope = null; // the parent scope
this.parent_scope = parent_scope; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables
});
AST_Node.DEFMETHOD("is_block_scope", return_false);
AST_Class.DEFMETHOD("is_block_scope", return_false);
AST_Lambda.DEFMETHOD("is_block_scope", return_false);
AST_Toplevel.DEFMETHOD("is_block_scope", return_false);
AST_SwitchBranch.DEFMETHOD("is_block_scope", return_false);
AST_Block.DEFMETHOD("is_block_scope", return_true);
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;
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
var def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
this.def_variable(new AST_SymbolConst({
name: "arguments",
start: this.start,
end: this.end
}));
});
AST_SymbolRef.DEFMETHOD("reference", function(options) {
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
def.references.push(this);
var s = this.scope;
while (s) {
push_uniq(s.enclosed, def);
@@ -262,6 +379,11 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
}
});
AST_Symbol.DEFMETHOD("reference", function(options) {
this.definition().references.push(this);
this.mark_enclosed(options);
});
AST_Scope.DEFMETHOD("find_variable", function(name){
if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name)
@@ -269,7 +391,9 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
});
AST_Scope.DEFMETHOD("def_function", function(symbol){
this.functions.set(symbol.name, this.def_variable(symbol));
var def = this.def_variable(symbol);
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol){
@@ -292,8 +416,8 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name excepted from mangling.
if (options.except.indexOf(m) >= 0) continue;
// shadow a name reserved from mangling.
if (options.reserved.indexOf(m) >= 0) continue;
// we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in
@@ -325,18 +449,12 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
});
AST_Symbol.DEFMETHOD("unmangleable", function(options){
return this.definition().unmangleable(options);
});
// property accessors are not mangleable
AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
return true;
var def = this.definition();
return !def || def.unmangleable(options);
});
// labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", function(){
return false;
});
AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function(){
return this.definition().references.length == 0
@@ -347,13 +465,9 @@ AST_Symbol.DEFMETHOD("undeclared", function(){
return this.definition().undeclared;
});
AST_LabelRef.DEFMETHOD("undeclared", function(){
return false;
});
AST_LabelRef.DEFMETHOD("undeclared", return_false);
AST_Label.DEFMETHOD("undeclared", function(){
return false;
});
AST_Label.DEFMETHOD("undeclared", return_false);
AST_Symbol.DEFMETHOD("definition", function(){
return this.thedef;
@@ -364,21 +478,23 @@ AST_Symbol.DEFMETHOD("global", function(){
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
return defaults(options, {
except : [],
options = defaults(options, {
eval : false,
sort : false, // Ignored. Flag retained for backwards compatibility.
ie8 : false,
keep_classnames: false,
keep_fnames : false,
reserved : [],
toplevel : false,
screw_ie8 : true,
keep_fnames : false
});
if (!Array.isArray(options.reserved)) options.reserved = [];
return options;
});
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options);
// Never mangle arguments
options.except.push('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
@@ -389,7 +505,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (options.cache) {
this.globals.each(function(symbol){
if (options.except.indexOf(symbol.name) < 0) {
if (options.reserved.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
});
@@ -406,7 +522,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (node instanceof AST_Scope) {
var p = tw.parent(), a = [];
node.variables.each(function(symbol){
if (options.except.indexOf(symbol.name) < 0) {
if (options.reserved.indexOf(symbol.name) < 0) {
a.push(symbol);
}
});
@@ -419,13 +535,18 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
node.mangled_name = name;
return true;
}
if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
var mangle_with_block_scope =
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
to_mangle.push(node.definition());
return;
}
});
this.walk(tw);
to_mangle.forEach(function(def){ def.mangle(options) });
to_mangle.forEach(function(def){
def.mangle(options);
});
if (options.cache) {
options.cache.cname = this.cname;
@@ -434,105 +555,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
options = this._default_mangler_options(options);
var tw = new TreeWalker(function(node){
if (node instanceof AST_Constant)
base54.consider(node.print_to_string());
else if (node instanceof AST_Return)
base54.consider("return");
else if (node instanceof AST_Throw)
base54.consider("throw");
else if (node instanceof AST_Continue)
base54.consider("continue");
else if (node instanceof AST_Break)
base54.consider("break");
else if (node instanceof AST_Debugger)
base54.consider("debugger");
else if (node instanceof AST_Directive)
base54.consider(node.value);
else if (node instanceof AST_While)
base54.consider("while");
else if (node instanceof AST_Do)
base54.consider("do while");
else if (node instanceof AST_If) {
base54.consider("if");
if (node.alternative) base54.consider("else");
try {
AST_Node.prototype.print = function(stream, force_parens) {
this._print(stream, force_parens);
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
base54.consider(this.name, -1);
} else if (options.properties) {
if (this instanceof AST_Dot) {
base54.consider(this.property, -1);
} else if (this instanceof AST_Sub) {
skip_string(this.property);
}
}
};
base54.consider(this.print_to_string(), 1);
} finally {
AST_Node.prototype.print = AST_Node.prototype._print;
}
else if (node instanceof AST_Var)
base54.consider("var");
else if (node instanceof AST_Const)
base54.consider("const");
else if (node instanceof AST_Lambda)
base54.consider("function");
else if (node instanceof AST_For)
base54.consider("for");
else if (node instanceof AST_ForIn)
base54.consider("for in");
else if (node instanceof AST_Switch)
base54.consider("switch");
else if (node instanceof AST_Case)
base54.consider("case");
else if (node instanceof AST_Default)
base54.consider("default");
else if (node instanceof AST_With)
base54.consider("with");
else if (node instanceof AST_ObjectSetter)
base54.consider("set" + node.key);
else if (node instanceof AST_ObjectGetter)
base54.consider("get" + node.key);
else if (node instanceof AST_ObjectKeyVal)
base54.consider(node.key);
else if (node instanceof AST_New)
base54.consider("new");
else if (node instanceof AST_This)
base54.consider("this");
else if (node instanceof AST_Try)
base54.consider("try");
else if (node instanceof AST_Catch)
base54.consider("catch");
else if (node instanceof AST_Finally)
base54.consider("finally");
else if (node instanceof AST_Symbol && node.unmangleable(options))
base54.consider(node.name);
else if (node instanceof AST_Unary || node instanceof AST_Binary)
base54.consider(node.operator);
else if (node instanceof AST_Dot)
base54.consider(node.property);
});
this.walk(tw);
base54.sort();
function skip_string(node) {
if (node instanceof AST_String) {
base54.consider(node.value, -1);
} else if (node instanceof AST_Conditional) {
skip_string(node.consequent);
skip_string(node.alternative);
} else if (node instanceof AST_Sequence) {
skip_string(node.expressions[node.expressions.length - 1]);
}
}
});
var base54 = (function() {
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
var digits = "0123456789".split("");
var chars, frequency;
function reset() {
frequency = Object.create(null);
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
chars.forEach(function(ch){ frequency[ch] = 0 });
leading.forEach(function(ch) {
frequency[ch] = 0;
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
}
base54.consider = function(str){
base54.consider = function(str, delta) {
for (var i = str.length; --i >= 0;) {
var code = str.charCodeAt(i);
if (code in frequency) ++frequency[code];
frequency[str[i]] += delta;
}
};
base54.sort = function() {
chars = mergeSort(chars, function(a, b){
if (is_digit(a) && !is_digit(b)) return 1;
if (is_digit(b) && !is_digit(a)) return -1;
function compare(a, b) {
return frequency[b] - frequency[a];
});
}
base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
};
base54.reset = reset;
reset();
base54.get = function(){ return chars };
base54.freq = function(){ return frequency };
function base54(num) {
var ret = "", base = 54;
num++;
do {
num--;
ret += String.fromCharCode(chars[num % base]);
ret += chars[num % base];
num = Math.floor(num / base);
base = 64;
} while (num > 0);
@@ -540,89 +625,3 @@ var base54 = (function() {
};
return base54;
})();
AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
options = defaults(options, {
undeclared : false, // this makes a lot of noise
unreferenced : true,
assign_to_global : true,
func_arguments : true,
nested_defuns : true,
eval : true
});
var tw = new TreeWalker(function(node){
if (options.undeclared
&& node instanceof AST_SymbolRef
&& node.undeclared())
{
// XXX: this also warns about JS standard names,
// i.e. Object, Array, parseInt etc. Should add a list of
// exceptions.
AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
name: node.name,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.assign_to_global)
{
var sym = null;
if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
sym = node.left;
else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
sym = node.init;
if (sym
&& (sym.undeclared()
|| (sym.global() && sym.scope !== sym.definition().scope))) {
AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
name: sym.name,
file: sym.start.file,
line: sym.start.line,
col: sym.start.col
});
}
}
if (options.eval
&& node instanceof AST_SymbolRef
&& node.undeclared()
&& node.name == "eval") {
AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
}
if (options.unreferenced
&& (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
&& !(node instanceof AST_SymbolCatch)
&& node.unreferenced()) {
AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
type: node instanceof AST_Label ? "Label" : "Symbol",
name: node.name,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.func_arguments
&& node instanceof AST_Lambda
&& node.uses_arguments) {
AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
name: node.name ? node.name.name : "anonymous",
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.nested_defuns
&& node instanceof AST_Defun
&& !(tw.parent() instanceof AST_Scope)) {
AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
name: node.name.name,
type: tw.parent().TYPE,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
});
this.walk(tw);
});

View File

@@ -163,10 +163,18 @@ TreeTransformer.prototype = new TreeWalker;
if (self.value) self.value = self.value.transform(tw);
});
_(AST_Destructuring, function(self, tw) {
self.names = do_list(self.names, tw);
});
_(AST_Lambda, function(self, tw){
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);
if (self.body instanceof AST_Node) {
self.body = self.body.transform(tw);
} else {
self.body = do_list(self.body, tw);
}
});
_(AST_Call, function(self, tw){
@@ -174,9 +182,8 @@ TreeTransformer.prototype = new TreeWalker;
self.args = do_list(self.args, tw);
});
_(AST_Seq, function(self, tw){
self.car = self.car.transform(tw);
self.cdr = self.cdr.transform(tw);
_(AST_Sequence, function(self, tw){
self.expressions = do_list(self.expressions, tw);
});
_(AST_Dot, function(self, tw){
@@ -188,6 +195,14 @@ TreeTransformer.prototype = new TreeWalker;
self.property = self.property.transform(tw);
});
_(AST_Yield, function(self, tw){
if (self.expression) self.expression = self.expression.transform(tw);
});
_(AST_Await, function(self, tw){
self.expression = self.expression.transform(tw);
});
_(AST_Unary, function(self, tw){
self.expression = self.expression.transform(tw);
});
@@ -212,7 +227,50 @@ TreeTransformer.prototype = new TreeWalker;
});
_(AST_ObjectProperty, function(self, tw){
if (self.key instanceof AST_Node) {
self.key = self.key.transform(tw);
}
self.value = self.value.transform(tw);
});
_(AST_Class, function(self, tw){
if (self.name) self.name = self.name.transform(tw);
if (self.extends) self.extends = self.extends.transform(tw);
self.properties = do_list(self.properties, tw);
});
_(AST_Expansion, function(self, tw){
self.expression = self.expression.transform(tw);
});
_(AST_NameMapping, function(self, tw) {
self.foreign_name = self.foreign_name.transform(tw);
self.name = self.name.transform(tw);
});
_(AST_Import, function(self, tw) {
if (self.imported_name) self.imported_name = self.imported_name.transform(tw);
if (self.imported_names) do_list(self.imported_names, tw);
self.module_name = self.module_name.transform(tw);
});
_(AST_Export, function(self, tw) {
if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw);
if (self.exported_value) self.exported_value = self.exported_value.transform(tw);
if (self.exported_names) do_list(self.exported_names, tw);
if (self.module_name) self.module_name = self.module_name.transform(tw);
});
_(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);
}
}
});
_(AST_PrefixedTemplateString, function(self, tw) {
self.template_string = self.template_string.transform(tw);
});
})();

View File

@@ -43,13 +43,6 @@
"use strict";
function array_to_hash(a) {
var ret = Object.create(null);
for (var i = 0; i < a.length; ++i)
ret[a[i]] = true;
return ret;
};
function slice(a, start) {
return Array.prototype.slice.call(a, start || 0);
};
@@ -126,9 +119,11 @@ function merge(obj, ext) {
return count;
};
function noop() {};
function noop() {}
function return_false() { return false; }
function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
var MAP = (function(){
function MAP(a, f, backwards) {
@@ -185,7 +180,7 @@ function push_uniq(array, el) {
function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){
return props[p];
return props && props[p];
});
};
@@ -344,7 +339,7 @@ function first_in_statement(stack) {
for (var i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Seq && p.car === node ) ||
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||

View File

@@ -1,10 +1,10 @@
{
"name": "uglify-js",
"name": "uglify-es",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"homepage": "http://lisperator.net/uglifyjs",
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "2.8.2",
"version": "3.0.22",
"engines": {
"node": ">=0.8.0"
},
@@ -29,26 +29,29 @@
"LICENSE"
],
"dependencies": {
"async": "~0.2.6",
"source-map": "~0.5.1",
"uglify-to-browserify": "~1.0.0",
"yargs": "~3.10.0"
"commander": "~2.9.0",
"source-map": "~0.5.1"
},
"devDependencies": {
"acorn": "~0.6.0",
"escodegen": "~1.3.3",
"esfuzz": "~0.3.1",
"estraverse": "~1.5.1",
"mocha": "~2.3.4"
},
"browserify": {
"transform": [
"uglify-to-browserify"
]
"acorn": "~5.0.3",
"mocha": "~2.3.4",
"semver": "~5.3.0"
},
"scripts": {
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
"test": "node test/run-tests.js"
},
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
"keywords": [
"uglify",
"uglify-js",
"uglify-es",
"minify",
"minifier",
"es5",
"es6",
"es2015",
"es2016",
"es2017",
"async",
"await"
]
}

View File

@@ -4,15 +4,16 @@
"use strict";
var createHash = require("crypto").createHash;
var fetch = require("./fetch");
var fork = require("child_process").fork;
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc", "warnings=false");
args.push("-mc");
}
args.push("--stats");
args.push("--timings");
var urls = [
"https://code.jquery.com/jquery-3.1.1.js",
"https://code.angularjs.org/1.6.1/angular.js",
"https://code.jquery.com/jquery-3.2.1.js",
"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js",
"https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js",
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
"https://unpkg.com/react@15.3.2/dist/react.js",
@@ -24,26 +25,53 @@ var results = {};
var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
var failures = [];
urls.forEach(function(url) {
var info = results[url];
console.log();
console.log(url);
console.log(results[url].time);
console.log("SHA1:", results[url].sha1);
console.log(info.log);
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("SHA1 sum:", info.sha1);
if (info.code) {
failures.push(url);
}
});
if (failures.length) {
console.error("Benchmark failed:");
failures.forEach(function(url) {
console.error(url);
});
process.exit(1);
}
}
}
urls.forEach(function(url) {
results[url] = { time: "" };
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
results[url] = {
input: 0,
output: 0,
log: ""
};
fetch(url, function(err, res) {
if (err) throw err;
var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
res.pipe(uglifyjs.stdin);
uglifyjs.stdout.pipe(createHash("sha1")).on("data", function(data) {
res.on("data", function(data) {
results[url].input += data.length;
}).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length;
}).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex");
done();
});
uglifyjs.stderr.setEncoding("utf8");
uglifyjs.stderr.on("data", function(data) {
results[url].time += data;
}).on("end", done)
results[url].log += data;
});
uglifyjs.on("exit", function(code) {
results[url].code = code;
done();
});
});
});

View File

@@ -1,67 +0,0 @@
ng_inject_defun: {
options = {
angular: true
};
input: {
/*@ngInject*/
function Controller(dependency) {
return dependency;
}
}
expect: {
function Controller(dependency) {
return dependency;
}
Controller.$inject=['dependency']
}
}
ng_inject_assignment: {
options = {
angular: true
};
input: {
/*@ngInject*/
var Controller = function(dependency) {
return dependency;
}
}
expect: {
var Controller = function(dependency) {
return dependency;
}
Controller.$inject=['dependency']
}
}
ng_inject_inline: {
options = {
angular: true
};
input: {
angular.module('a').
factory('b',
/*@ngInject*/
function(dependency) {
return dependency;
}).
directive('c',
/*@ngInject*/
function(anotherDependency) {
return anotherDependency;
})
}
expect: {
angular.module('a').
factory('b',[
'dependency',
function(dependency) {
return dependency;
}]).
directive('c',[
'anotherDependency',
function(anotherDependency) {
return anotherDependency;
}])
}
}

View File

@@ -1,3 +1,5 @@
// NOTE trailing comma doesn't contribute to length of an array
// That also means the array changes length if previous element is a hole too and got cut off
holes_and_undefined: {
input: {
w = [1,,];
@@ -91,6 +93,79 @@ constant_join_2: {
}
}
spread_with_variable_as_last_element: {
input: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values];
}
expect: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values];
}
}
spread_with_variable_in_middle: {
input: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values, 7,,,];
}
expect: {
var values = [4, 5, 6];
var a = [1, 2, 3, ...values, 7,,,];
}
}
spread_with_variable_at_front: {
input: {
var values = [1, 2, 3];
var a = [...values, 4, 5, 6];
}
expect: {
var values = [1, 2, 3];
var a = [...values, 4, 5, 6];
}
}
spread_with_variable_at_front_after_elisions: {
input: {
var values = [1, 2, 3];
var a = [,,,...values, 4, 5, 6];
}
expect: {
var values = [1, 2, 3];
var a = [,,,...values, 4, 5, 6];
}
}
spread_with_array_at_end: {
input: {
var a = [1, 2, ...[4, 5, 6]];
}
expect: {
var a = [1, 2, ...[4, 5, 6]];
}
}
spread_with_logical_expression_at_end: {
options = { evaluate: true }
input: {
var a = [1, 2, 3, ...[2+2]]
}
expect: {
var a = [1, 2, 3, ...[4]]
}
}
spread_with_logical_expression_at_middle: {
options = { evaluate: true }
input: {
var a = [1, 1, ...[1+1, 1+2, 2+3], 8]
}
expect: {
var a = [1, 1, ...[2, 3, 5], 8]
}
}
constant_join_3: {
options = {
unsafe: true,

540
test/compress/arrow.js Normal file
View File

@@ -0,0 +1,540 @@
arrow_functions_without_body: {
input: {
var a1 = () => 42;
var a2 = (p) => p;
var a3 = p => p;
var a4 = (...p) => p;
var a5 = (b, c) => b + c;
var a6 = (b, ...c) => b + c[0];
var a7 = (...b) => b.join();
}
expect: {
var a1 = () => 42;
var a2 = (p) => p;
var a3 = p => p;
var a4 = (...p) => p;
var a5 = (b, c) => b + c;
var a6 = (b, ...c) => b + c[0];
var a7 = (...b) => b.join();
}
}
arrow_functions_with_body: {
input: {
var a1 = () => {
var a = 42 * Math.random();
return a;
};
var a2 = (p) => {
var a = Math.random() * p;
return a;
};
var a3 = p => {
var a = Math.random() * p;
return a;
};
var a4 = (...p) => {
var a = Math.random() * p;
return a;
};
var a5 = (b, c) => {
var result = b * c + b / c;
return result
};
var a6 = (b, ...c) => {
var result = b;
for (var i = 0; i < c.length; i++)
result += c[i];
return result
};
var a7 = (...b) => {
b.join();
}
}
expect: {
var a1 = () => {
var a = 42 * Math.random();
return a;
};
var a2 = (p) => {
var a = Math.random() * p;
return a;
};
var a3 = p => {
var a = Math.random() * p;
return a;
};
var a4 = (...p) => {
var a = Math.random() * p;
return a;
};
var a5 = (b, c) => {
var result = b * c + b / c;
return result
};
var a6 = (b, ...c) => {
var result = b;
for (var i = 0; i < c.length; i++)
result += c[i];
return result
};
var a7 = (...b) => {
b.join();
};
}
}
arrow_function_with_single_parameter_with_default: {
input: {
var foo = (a = 0) => doSomething(a);
}
expect_exact: "var foo=(a=0)=>doSomething(a);"
}
arrow_binding_pattern: {
input: {
var foo = ([]) => "foo";
var bar = ({}) => "bar";
var with_default = (foo = "default") => foo;
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
var array_after_spread = (...[foo]) => foo;
var array_after_spread = (...{foo}) => foo;
var computed = ({ [compute()]: x }) => {};
var array_hole = ([, , ...x] = [1, 2]) => {};
var object_trailing_elision = ({foo,}) => {};
var spread_empty_array = (...[]) => "foo";
var spread_empty_object = (...{}) => "foo";
}
expect: {
var foo = ([]) => "foo";
var bar = ({}) => "bar";
var with_default = (foo = "default") => foo;
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
var array_after_spread = (...[foo]) => foo;
var array_after_spread = (...{foo}) => foo;
var computed = ({ [compute()]: x }) => {};
var array_hole = ([, , ...x] = [1, 2]) => {};
var object_trailing_elision = ({foo,}) => {};
var spread_empty_array = (...[]) => "foo";
var spread_empty_object = (...{}) => "foo";
}
}
arrow_binding_pattern_strict: {
input: {
var foo = ([,]) => "foo";
}
expect_exact: 'var foo=([,])=>"foo";'
}
arrow_with_regexp: {
input: {
num => /\d{11,14}/.test( num )
}
expect: {
num => /\d{11,14}/.test( num )
}
}
arrow_unused: {
options = {
toplevel: false,
side_effects: true,
unused: true,
}
input: {
top => dog;
let fn = a => { console.log(a * a); };
let u = (x, y) => x - y + g;
(() => { console.log("0"); })();
!function(x) {
(() => { console.log("1"); })();
let unused = x => { console.log(x); };
let baz = e => e + e;
console.log(baz(x));
}(1);
fn(3);
}
expect: {
let fn = a => { console.log(a * a); };
let u = (x, y) => x - y + g;
(() => { console.log("0"); })();
!function(x) {
(() => { console.log("1"); })();
let baz = e => e + e;
console.log(baz(x));
}(1);
fn(3);
}
expect_stdout: [ "0", "1", "2", "9" ]
node_version: ">=6"
}
arrow_unused_toplevel: {
options = {
toplevel: true,
side_effects: true,
unused: true,
}
input: {
top => dog;
let fn = a => { console.log(a * a); };
let u = (x, y) => x - y + g;
(() => { console.log("0"); })();
!function(x) {
(() => { console.log("1"); })();
let unused = x => { console.log(x); };
let baz = e => e + e;
console.log(baz(x));
}(1);
fn(3);
}
expect: {
let fn = a => { console.log(a * a); };
(() => { console.log("0"); })();
!function(x) {
(() => { console.log("1"); })();
let baz = e => e + e;
console.log(baz(x));
}(1);
fn(3);
}
expect_stdout: [ "0", "1", "2", "9" ]
node_version: ">=6"
}
no_leading_parentheses: {
input: {
(x,y) => x(y);
async (x,y) => await x(y);
}
expect_exact: "(x,y)=>x(y);async(x,y)=>await x(y);"
}
async_identifiers: {
options = {
arrows: true,
ecma: 6,
}
input: {
var async = function(x){ console.log("async", x); };
var await = function(x){ console.log("await", x); };
async(1);
await(2);
}
expect: {
var async = x => { console.log("async", x); };
var await = x => { console.log("await", x); };
async(1);
await(2);
}
expect_stdout: [
"async 1",
"await 2",
]
node_version: ">=4"
}
async_function_expression: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
side_effects: true,
}
input: {
var named = async function foo() {
await bar(1 + 0) + (2 + 0);
}
var anon = async function() {
await (1 + 0) + bar(2 + 0);
}
}
expect: {
var named = async function foo() {
await bar(1);
};
var anon = async () => {
await 1, bar(2);
};
}
}
issue_27: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
unused: true,
}
input: {
(function(jQuery) {
var $;
$ = jQuery;
$("body").addClass("foo");
})(jQuery);
}
expect: {
(jQuery => {
jQuery("body").addClass("foo");
})(jQuery);
}
}
issue_2105_1: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
} );
});
}
expect: {
void (() => {
var quux = () => {
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
((factory) => {
factory();
})( () => {
return ((fn) => {
fn()().prop();
})( () => {
let bar = () => {
var quux = () => {
console.log("PASS");
}, foo = () => {
console.log;
quux();
};
return { prop: foo };
};
return bar;
} );
});
}
expect: {
void (() => {
var quux = () => {
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2136_2: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
inline: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
console.log(x);
}
!function(a, ...b) {
f(b[0]);
}(1, 2, 3);
}
expect: {
function f(x) {
console.log(x);
}
f([2,3][0]);
}
expect_stdout: "2"
node_version: ">=6"
}
issue_2136_3: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
evaluate: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function f(x) {
console.log(x);
}
!function(a, ...b) {
f(b[0]);
}(1, 2, 3);
}
expect: {
console.log(2);
}
expect_stdout: "2"
node_version: ">=6"
}
call_args: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
inline: true,
reduce_vars: true,
}
input: {
const a = 1;
console.log(a);
+function(a) {
return a;
}(a);
}
expect: {
const a = 1;
console.log(1);
+(1, 1);
}
expect_stdout: true
}
call_args_drop_param: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
inline: true,
keep_fargs: false,
reduce_vars: true,
unused: true,
}
input: {
const a = 1;
console.log(a);
+function(a) {
return a;
}(a, b);
}
expect: {
const a = 1;
console.log(1);
+(b, 1);
}
expect_stdout: true
}
issue_485_crashing_1530: {
options = {
arrows: true,
conditionals: true,
dead_code: true,
ecma: 6,
evaluate: true,
inline: true,
}
input: {
(function(a) {
if (true) return;
var b = 42;
})(this);
}
expect: {
this, void 0;
}
}
issue_2084: {
options = {
arrows: true,
collapse_vars: true,
conditionals: true,
ecma: 6,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
!function() {
!function(c) {
c = 1 + c;
var c = 0;
function f14(a_1) {
if (c = 1 + c, 0 !== 23..toString())
c = 1 + c, a_1 && (a_1[0] = 0);
}
f14();
}(-1);
}();
console.log(c);
}
expect: {
var c = 0;
((c) => {
c = 1 + c,
c = 1 + (c = 0),
0 !== 23..toString() && (c = 1 + c);
})(-1),
console.log(c);
}
expect_stdout: "0"
node_version: ">=4"
}

View File

@@ -2,7 +2,7 @@ ascii_only_true: {
options = {}
beautify = {
ascii_only : true,
screw_ie8 : true,
ie8 : false,
beautify : false,
}
input: {
@@ -20,7 +20,7 @@ ascii_only_false: {
options = {}
beautify = {
ascii_only : false,
screw_ie8 : true,
ie8 : false,
beautify : false,
}
input: {
@@ -33,4 +33,3 @@ ascii_only_false: {
}
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\'}'
}

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

@@ -0,0 +1,294 @@
await_precedence: {
input: {
async function f1() { await x + y; }
async function f2() { await (x + y); }
}
expect_exact: "async function f1(){await x+y}async function f2(){await(x+y)}"
}
await_precedence_prop: {
input: {
async function f1(){ return (await foo()).bar; }
async function f2(){ return (await foo().bar); }
}
expect_exact: "async function f1(){return(await foo()).bar}async function f2(){return await foo().bar}"
}
await_precedence_call: {
input: {
async function f3(){ return (await foo())(); }
async function f4(){ return await (foo()()); }
}
expect_exact: "async function f3(){return(await foo())()}async function f4(){return await foo()()}"
}
async_function_declaration: {
options = {
side_effects: true,
unused: true,
}
input: {
async function f0() {}
async function f1() { await x + y; }
async function f2() { await (x + y); }
async function f3() { await x + await y; }
async function f4() { await (x + await y); }
async function f5() { await x; await y; }
async function f6() { await x, await y; }
}
expect: {
async function f0() {}
async function f1() { await x, y; }
async function f2() { await (x + y); }
async function f3() { await x, await y; }
async function f4() { await (x + await y); }
async function f5() { await x; await y; }
async function f6() { await x, await y; }
}
}
async_function_expression: {
options = {
evaluate: true,
side_effects: true,
unused: true,
}
input: {
var named = async function foo() {
await bar(1 + 0) + (2 + 0);
}
var anon = async function() {
await (1 + 0) + bar(2 + 0);
}
}
expect: {
var named = async function() {
await bar(1);
};
var anon = async function() {
await 1, bar(2);
};
}
}
async_class: {
options = {
evaluate: true,
}
input: {
class Foo {
async m1() {
return await foo(1 + 2);
}
static async m2() {
return await foo(3 + 4);
}
}
}
expect: {
class Foo {
async m1() {
return await foo(3);
}
static async m2() {
return await foo(7);
}
}
}
}
async_object_literal: {
options = {
evaluate: true,
}
input: {
var obj = {
async a() {
await foo(1 + 0);
},
anon: async function(){
await foo(2 + 0);
}
};
}
expect: {
var obj = {
async a() {
await foo(1);
},
anon: async function() {
await foo(2);
}
};
}
}
async_export: {
input: {
export async function run() {};
export default async function def() {};
}
expect: {
export async function run() {};
export default async function def() {};
}
}
async_inline: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(async function(){ return await 3; })();
(async function(x){ await console.log(x); })(4);
function echo(x) { return x; }
echo( async function(){ return await 1; }() );
echo( async function(x){ await console.log(x); }(2) );
function top() { console.log("top"); }
top();
async function async_top() { console.log("async_top"); }
async_top();
}
expect: {
!async function(){await 3}();
!async function(x){await console.log(4)}();
function echo(x){return x}
echo(async function(){return await 1}());
echo(async function(x){await console.log(2)}());
console.log("top");
!async function(){console.log("async_top")}();
}
expect_stdout: [
"4",
"2",
"top",
"async_top",
]
node_version: ">=8"
}
async_identifiers: {
input: {
var async = function(x){ console.log("async", x); };
var await = function(x){ console.log("await", x); };
async(1);
await(2);
}
expect: {
var async = function(x){ console.log("async", x); };
var await = function(x){ console.log("await", x); };
async(1);
await(2);
}
expect_stdout: [
"async 1",
"await 2",
]
}
async_shorthand_property: {
mangle = {
toplevel: true,
}
input: {
function print(o) { console.log(o.async + " " + o.await); }
var async = "Async", await = "Await";
print({ async });
print({ await });
print({ async, await });
print({ await, async });
print({ async: async });
print({ await: await });
print({ async: async, await: await });
print({ await: await, async: async });
}
expect: {
function a(a) { console.log(a.async + " " + a.await); }
var n = "Async", c = "Await";
a({ async: n });
a({ await: c });
a({ async: n, await: c });
a({ await: c, async: n });
a({ async: n });
a({ await: c });
a({ async: n, await: c });
a({ await: c, async: n });
}
expect_stdout: [
"Async undefined",
"undefined Await",
"Async Await",
"Async Await",
"Async undefined",
"undefined Await",
"Async Await",
"Async Await",
]
node_version: ">=4"
}
async_arrow: {
input: {
let a1 = async x => await foo(x);
let a2 = async () => await bar();
let a3 = async (x) => await baz(x);
let a4 = async (x, y) => { await far(x, y); }
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
}
expect: {
let a1 = async x => await foo(x);
let a2 = async () => await bar();
let a3 = async (x) => await baz(x);
let a4 = async (x, y) => { await far(x, y); }
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
}
}
async_arrow_wait: {
input: {
var a = async (x, y) => await x(y);
}
expect_exact: "var a=async(x,y)=>await x(y);"
}
async_arrow_iife: {
input: {
(async () => {
await fetch({});
})();
}
expect_exact: "(async()=>{await fetch({})})();"
}
async_arrow_iife_negate_iife: {
options = {
negate_iife: true,
}
input: {
(async () => {
await fetch();
})();
(() => {
plain();
})();
}
expect_exact: "(async()=>{await fetch()})();(()=>{plain()})();"
}

View File

@@ -0,0 +1,191 @@
let_statement: {
input: {
let x = 6;
}
expect_exact: "let x=6;"
}
do_not_hoist_let: {
options = {
hoist_vars: true,
};
input: {
function x() {
if (FOO) {
let let1;
let let2;
var var1;
var var2;
}
}
}
expect: {
function x() {
var var1, var2;
if (FOO) {
let let1;
let let2;
}
}
}
}
do_not_remove_anon_blocks_if_they_have_decls: {
input: {
function x() {
{
let x;
}
{
var x;
}
{
const y;
class Zee {};
}
}
{
let y;
}
{
var y;
}
}
expect: {
function x(){
{
let x
}
var x;
{
const y;
class Zee {}
}
}
{
let y
}
var y;
}
}
remove_unused_in_global_block: {
options = {
unused: true,
}
input: {
{
let x;
const y;
class Zee {};
var w;
}
let ex;
const why;
class Zed {};
var wut;
console.log(x, y, Zee);
}
expect: {
var w;
let ex;
const why;
class Zed {};
var wut;
console.log(x, y, Zee);
}
}
regression_block_scope_resolves: {
mangle = { };
options = {
dead_code: false
};
input: {
(function () {
if (1) {
let x;
const y = 1;
class Zee {};
}
if (1) {
let ex;
const why = 2;
class Zi {};
}
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
}());
}
expect: {
(function () {
if (1) {
let e;
const o = 1;
class t {};
}
if (1) {
let e;
const o = 2;
class t {};
}
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
}());
}
expect_stdout: "undefined undefined undefined undefined undefined undefined"
node_version: ">=6"
}
switch_block_scope_mangler: {
mangle = {}
input: {
var fn = function(code) {
switch (code) {
case 1:
let apple = code + 1;
let dog = code + 4;
console.log(apple, dog);
break;
case 2:
let banana = code + 2;
console.log(banana);
break;
default:
let cat = code + 3;
console.log(cat);
}
};
fn(1);
fn(2);
fn(3);
}
expect: {
var fn = function(e) {
switch (e) {
case 1:
let l = e + 1
let o = e + 4;
console.log(l, o);
break;
case 2:
let n = e + 2;
console.log(n);
break;
default:
let c = e + 3;
console.log(c);
}
};
fn(1);
fn(2);
fn(3);
}
expect_stdout: [
"2 5",
"4",
"6",
]
node_version: ">=6"
}

View File

@@ -47,3 +47,142 @@ keep_some_blocks: {
} else stuff();
}
}
issue_1664: {
input: {
var a = 1;
function f() {
if (undefined) a = 2;
{
function undefined() {}
undefined();
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
if (undefined) a = 2;
{
function undefined() {}
undefined();
}
}
f();
console.log(a);
}
expect_stdout: "1"
node_version: ">=6"
}
issue_1672_for: {
input: {
switch (function() {
return xxx;
}) {
case xxx:
for (; console.log("FAIL");) {
function xxx() {}
}
break;
}
}
expect: {
switch (function() {
return xxx;
}) {
case xxx:
for (; console.log("FAIL");) {
function xxx() {}
}
break;
}
}
expect_stdout: true
node_version: ">=6"
}
issue_1672_for_strict: {
input: {
"use strict";
switch (function() {
return xxx;
}) {
case xxx:
for (; console.log("FAIL");) {
function xxx() {}
}
break;
}
}
expect: {
"use strict";
switch (function() {
return xxx;
}) {
case xxx:
for (; console.log("FAIL");) {
function xxx() {}
}
break;
}
}
expect_stdout: true
node_version: ">=6"
}
issue_1672_if: {
input: {
switch (function() {
return xxx;
}) {
case xxx:
if (console.log("FAIL")) {
function xxx() {}
}
break;
}
}
expect: {
switch (function() {
return xxx;
}) {
case xxx:
if (console.log("FAIL")) function xxx() {}
break;
}
}
expect_stdout: true
node_version: ">=6"
}
issue_1672_if_strict: {
input: {
"use strict";
switch (function() {
return xxx;
}) {
case xxx:
if (console.log("FAIL")) {
function xxx() {}
}
break;
}
}
expect: {
"use strict";
switch (function() {
return xxx;
}) {
case xxx:
if (console.log("FAIL")) {
function xxx() {}
}
break;
}
}
expect_stdout: true
node_version: ">=6"
}

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,7 @@ concat_2: {
"1" + "2" + "3"
);
}
expect_stdout: true
}
concat_3: {
@@ -79,6 +80,7 @@ concat_3: {
1 + 2 + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_4: {
@@ -107,6 +109,7 @@ concat_4: {
1 + "2" + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_5: {
@@ -135,6 +138,7 @@ concat_5: {
"1" + 2 + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_6: {
@@ -163,4 +167,57 @@ concat_6: {
"1" + "2" + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_7: {
input: {
console.log(
"" + 1,
"" + "1",
"" + 1 + 2,
"" + 1 + "2",
"" + "1" + 2,
"" + "1" + "2",
"" + (x += "foo")
);
}
expect: {
console.log(
"" + 1,
"1",
"" + 1 + 2,
1 + "2",
"1" + 2,
"1" + "2",
x += "foo"
);
}
expect_stdout: true
}
concat_8: {
input: {
console.log(
1 + "",
"1" + "",
1 + 2 + "",
1 + "2" + "",
"1" + 2 + "",
"1" + "2" + "",
(x += "foo") + ""
);
}
expect: {
console.log(
1 + "",
"1",
1 + 2 + "",
1 + "2",
"1" + 2,
"1" + "2",
x += "foo"
);
}
expect_stdout: true
}

View File

@@ -797,3 +797,221 @@ no_evaluate: {
}
}
}
equality_conditionals_false: {
options = {
conditionals: false,
sequences: true,
}
input: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0);
f(0, true, 0);
f(1, 2, 3);
f(1, null, 3);
f(NaN);
f(NaN, "foo");
}
expect: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0),
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(NaN),
f(NaN, "foo");
}
expect_stdout: true
}
equality_conditionals_true: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0);
f(0, true, 0);
f(1, 2, 3);
f(1, null, 3);
f(NaN);
f(NaN, "foo");
}
expect: {
function f(a, b, c) {
console.log(
(b, a == a),
a == (b ? a : c),
(b, a != a),
a != (b ? a : c),
(b, a === a),
a === (b ? a : c),
(b, a !== a),
a !== (b ? a : c)
);
}
f(0, 0, 0),
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(NaN),
f(NaN, "foo");
}
expect_stdout: true
}
issue_1645_1: {
options = {
conditionals: true,
}
input: {
var a = 100, b = 10;
(b = a) ? a++ + (b += a) ? b += a : b += a : b ^= a;
console.log(a, b);
}
expect: {
var a = 100, b = 10;
(b = a) ? (a++ + (b += a), b += a) : b ^= a;
console.log(a,b);
}
expect_stdout: true
}
issue_1645_2: {
options = {
conditionals: true,
}
input: {
var a = 0;
function f() {
return a++;
}
f() ? a += 2 : a += 4;
console.log(a);
}
expect: {
var a = 0;
function f(){
return a++;
}
f() ? a += 2 : a += 4;
console.log(a);
}
expect_stdout: true
}
condition_symbol_matches_consequent: {
options = {
conditionals: true,
}
input: {
function foo(x, y) {
return x ? x : y;
}
function bar() {
return g ? g : h;
}
var g = 4;
var h = 5;
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
}
expect: {
function foo(x, y) {
return x || y;
}
function bar() {
return g || h;
}
var g = 4;
var h = 5;
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
}
expect_stdout: "3 7 true 4"
}
delete_conditional_1: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
side_effects: true,
}
input: {
console.log(delete (1 ? undefined : x));
console.log(delete (1 ? void 0 : x));
console.log(delete (1 ? Infinity : x));
console.log(delete (1 ? 1 / 0 : x));
console.log(delete (1 ? NaN : x));
console.log(delete (1 ? 0 / 0 : x));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
delete_conditional_2: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (0 ? x : undefined));
console.log(delete (0 ? x : void 0));
console.log(delete (0 ? x : Infinity));
console.log(delete (0 ? x : 1 / 0));
console.log(delete (0 ? x : NaN));
console.log(delete (0 ? x : 0 / 0));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}

View File

@@ -162,4 +162,5 @@ regexp_literal_not_const: {
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
})();
}
expect_stdout: true
}

View File

@@ -31,7 +31,7 @@ dead_code_2_should_warn: {
function f() {
g();
x = 10;
throw "foo";
throw new Error("foo");
// completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope.
@@ -46,16 +46,60 @@ dead_code_2_should_warn: {
})();
}
}
f();
}
expect: {
function f() {
g();
x = 10;
throw "foo";
throw new Error("foo");
var x;
var g;
}
f();
}
expect_stdout: true
node_version: ">=6"
}
dead_code_2_should_warn_strict: {
options = {
dead_code: true
};
input: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
// completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope.
if (x) {
y();
var x;
function g(){};
// but nested declarations should not be kept.
(function(){
var q;
function y(){};
})();
}
}
f();
}
expect: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
var x;
}
f();
}
expect_stdout: true
node_version: ">=4"
}
dead_code_constant_boolean_should_warn_more: {
@@ -78,14 +122,76 @@ dead_code_constant_boolean_should_warn_more: {
foo();
var moo;
}
bar();
}
expect: {
var foo;
function bar() {}
var bar;
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
bar();
}
expect_stdout: true
node_version: ">=6"
}
dead_code_constant_boolean_should_warn_more_strict: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
side_effects : true,
};
input: {
"use strict";
while (!((foo && bar) || (x + "0"))) {
console.log("unreachable");
var foo;
function bar() {}
}
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
asdf();
foo();
var moo;
}
bar();
}
expect: {
"use strict";
var foo;
// nothing for the while
// as for the for, it should keep:
var x = 10, y;
var moo;
bar();
}
expect_stdout: true
node_version: ">=4"
}
dead_code_block_decls_die: {
options = {
dead_code : true,
conditionals : true,
booleans : true,
evaluate : true
};
input: {
if (0) {
let foo = 6;
const bar = 12;
class Baz {};
var qux;
}
console.log(foo, bar, Baz);
}
expect: {
var qux;
console.log(foo, bar, Baz);
}
}
@@ -111,8 +217,9 @@ dead_code_const_declaration: {
var unused;
const CONST_FOO = !1;
var moo;
function bar() {}
var bar;
}
expect_stdout: true
}
dead_code_const_annotation: {
@@ -123,6 +230,7 @@ dead_code_const_annotation: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused;
@@ -137,8 +245,9 @@ dead_code_const_annotation: {
var unused;
var CONST_FOO_ANN = !1;
var moo;
function bar() {}
var bar;
}
expect_stdout: true
}
dead_code_const_annotation_regex: {
@@ -162,6 +271,7 @@ dead_code_const_annotation_regex: {
var CONST_FOO_ANN = !1;
CONST_FOO_ANN && console.log('reachable');
}
expect_stdout: true
}
dead_code_const_annotation_complex_scope: {
@@ -172,6 +282,7 @@ dead_code_const_annotation_complex_scope: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused_var;
@@ -201,9 +312,68 @@ dead_code_const_annotation_complex_scope: {
var CONST_FOO_ANN = !1;
var unused_var_2;
var moo;
function bar() {}
var bar;
var beef = 'good';
var meat = 'beef';
var pork = 'bad';
}
expect_stdout: true
}
try_catch_finally: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
var a = 1;
!function() {
try {
if (false) throw x;
} catch (a) {
var a = 2;
console.log("FAIL");
} finally {
a = 3;
console.log("PASS");
}
}();
try {
console.log(a);
} finally {
}
}
expect: {
var a = 1;
!function() {
var a;
a = 3;
console.log("PASS");
}();
try {
console.log(a);
} finally {
}
}
expect_stdout: [
"PASS",
"1",
]
}
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}

View File

@@ -0,0 +1,661 @@
destructuring_arrays: {
input: {
{const [aa, bb] = cc;}
{const [aa, [bb, cc]] = dd;}
{let [aa, bb] = cc;}
{let [aa, [bb, cc]] = dd;}
var [aa, bb] = cc;
var [aa, [bb, cc]] = dd;
var [,[,,,,,],,,zz,] = xx; // Trailing comma
var [,,zzz,,] = xxx; // Trailing comma after hole
}
expect: {
{const [aa, bb] = cc;}
{const [aa, [bb, cc]] = dd;}
{let [aa, bb] = cc;}
{let [aa, [bb, cc]] = dd;}
var [aa, bb] = cc;
var [aa, [bb, cc]] = dd;
var [,[,,,,,],,,zz] = xx;
var [,,zzz,,] = xxx;
}
}
destructuring_arrays_holes: {
input: {
var [,,,,] = a;
var [,,b,] = c;
var [d,,] = e;
}
expect_exact: "var[,,,,]=a;var[,,b]=c;var[d,,]=e;"
}
destructuring_objects: {
input: {
{const {aa, bb} = {aa:1, bb:2};}
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb} = {aa:1, bb:2};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb} = {aa:1, bb:2};
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
}
expect: {
{const {aa, bb} = {aa:1, bb:2};}
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb} = {aa:1, bb:2};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
var {aa, bb} = {aa:1, bb:2};
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
}
}
destructuring_objects_trailing_elision: {
beautify = {
ecma: 6
}
input: {
var {cc,} = foo;
}
expect_exact: "var{cc}=foo;"
}
nested_destructuring_objects: {
beautify = {
ecma: 6
}
input: {
const [{a},b] = c;
let [{a},b] = c;
var [{a},b] = c;
}
expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;';
}
destructuring_constdef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (const [x,y] in pairs);
for (const [a] = 0;;);
for (const {c} of cees);
}
expect_exact: "for(const[x,y]in pairs);for(const[a]=0;;);for(const{c}of cees);"
}
destructuring_letdef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (let [x,y] in pairs);
for (let [a] = 0;;);
for (let {c} of cees);
}
expect_exact: "for(let[x,y]in pairs);for(let[a]=0;;);for(let{c}of cees);"
}
destructuring_vardef_in_loops: {
beautify = {
ecma: 6
}
input: {
for (var [x,y] in pairs);
for (var [a] = 0;;);
for (var {c} of cees);
}
expect_exact: "for(var[x,y]in pairs);for(var[a]=0;;);for(var{c}of cees);"
}
destructuring_expressions: {
beautify = {
ecma: 6
}
input: {
({a, b});
[{a}];
f({x});
}
expect_exact: "({a,b});[{a}];f({x});"
}
destructuring_remove_unused_1: {
options = {
unused: true
}
input: {
function a() {
var unused = "foo";
var a = [1];
var [b] = a;
f(b);
}
function b() {
var unused = "foo";
var a = {b: 1};
var {b} = a;
f(b);
}
function c() {
var unused = "foo";
var a = [[1]];
var [[b]] = a;
f(b);
}
function d() {
var unused = "foo";
var a = {b: {b:1}};
var {b:{b}} = a;
f(b);
}
function e() {
var unused = "foo";
var a = [1, 2, 3, 4, 5];
var x = [[1, 2, 3]];
var y = {h: 1};
var [b, ...c] = a;
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
expect: {
function a() {
var a = [1];
var [b] = a;
f(b);
}
function b() {
var a = {b: 1};
var {b} = a;
f(b);
}
function c() {
var a = [[1]];
var [[b]] = a;
f(b);
}
function d() {
var a = {b: {b:1}};
var {b:{b}} = a;
f(b);
}
function e() {
var a = [1, 2, 3, 4, 5];
var x = [[1, 2, 3]];
var y = {h: 1};
var [b, ...c] = a;
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
}
destructuring_remove_unused_2: {
options = {
unused: true
}
input: {
function a() {
var unused = "foo";
var a = [,,1];
var [b] = a;
f(b);
}
function b() {
var unused = "foo";
var a = [{a: [1]}];
var [{b: a}] = a;
f(b);
}
}
expect: {
function a() {
var a = [,,1];
var [b] = a;
f(b);
}
function b() {
var a = [{a: [1]}];
var [{b: a}] = a;
f(b);
}
}
}
object_destructuring_may_need_parentheses: {
beautify = {
ecma: 6
}
input: {
({a, b} = {a: 1, b: 2});
}
expect_exact: "({a,b}={a:1,b:2});"
}
destructuring_with_undefined_as_default_assignment: {
options = {
evaluate: true
}
input: {
[foo = undefined] = bar;
[foo = void 0] = bar;
}
expect: {
[foo] = bar;
[foo] = bar;
}
}
destructuring_dont_evaluate_with_undefined_as_default_assignment: {
options = {
evaluate: false
}
input: {
[foo = undefined] = bar;
}
expect: {
[foo = void 0] = bar;
}
}
reduce_vars: {
options = {
reduce_vars: true,
}
input: {
{const [aa, [bb, cc]] = dd;}
{let [aa, [bb, cc]] = dd;}
var [aa, [bb, cc]] = dd;
[aa, [bb, cc]] = dd;
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
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;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);
for (var [x,y] in pairs);
for ([x,y] in pairs);
}
expect: {
{const [aa, [bb, cc]] = dd;}
{let [aa, [bb, cc]] = dd;}
var [aa, [bb, cc]] = dd;
[aa, [bb, cc]] = dd;
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
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;
[{a},b] = c;
for (const [x,y] in pairs);
for (let [x,y] in pairs);
for (var [x,y] in pairs);
for ([x,y] in pairs);
}
}
unused: {
options = {
unused: true,
}
input: {
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
console.log(a);
}
expect: {
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
console.log(a);
}
}
issue_1886: {
options = {
collapse_vars: true,
}
input: {
let [a] = [1];
console.log(a);
}
expect: {
let [a] = [1];
console.log(a);
}
}
destructuring_decl_of_numeric_key: {
options = {
evaluate: true,
unused: true,
}
input: {
let { 3: x } = { [1 + 2]: 42 };
console.log(x);
}
expect: {
let { 3: x } = { [3]: 42 };
console.log(x);
}
expect_stdout: "42"
node_version: ">=6"
}
destructuring_decl_of_computed_key: {
options = {
evaluate: true,
unused: true,
}
input: {
let four = 4;
let { [7 - four]: x } = { [1 + 2]: 42 };
console.log(x);
}
expect: {
let four = 4;
let { [7 - four]: x } = { [3]: 42 };
console.log(x);
}
expect_stdout: "42"
node_version: ">=6"
}
destructuring_assign_of_numeric_key: {
options = {
evaluate: true,
unused: true,
}
input: {
let x;
({ 3: x } = { [1 + 2]: 42 });
console.log(x);
}
expect: {
let x;
({ 3: x } = { [3]: 42 });
console.log(x);
}
expect_stdout: "42"
node_version: ">=6"
}
destructuring_assign_of_computed_key: {
options = {
evaluate: true,
unused: true,
}
input: {
let x;
let four = 4;
({ [(5 + 2) - four]: x } = { [1 + 2]: 42 });
console.log(x);
}
expect: {
let x;
let four = 4;
({ [7 - four]: x } = { [3]: 42 });
console.log(x);
}
expect_stdout: "42"
node_version: ">=6"
}
mangle_destructuring_decl: {
options = {
evaluate: true,
unused: true,
}
mangle = {
}
input: {
function test(opts) {
let a = opts.a || { e: 7, n: 8 };
let { t, e, n, s = 5 + 4, o, r } = a;
console.log(t, e, n, s, o, r);
}
test({a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 }});
test({});
}
expect: {
function test(t) {
let e = t.a || { e: 7, n: 8 };
let {t: n, e: o, n: s, s: l = 9, o: a, r: c} = e;
console.log(n, o, s, l, a, c);
}
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
test({});
}
expect_stdout: [
"1 2 3 4 5 6",
"undefined 7 8 9 undefined undefined",
]
node_version: ">=6"
}
mangle_destructuring_assign_toplevel_true: {
options = {
toplevel: true,
evaluate: true,
unused: true,
}
mangle = {
toplevel: true,
}
beautify = {
ecma: 6
}
input: {
function test(opts) {
let s, o, r;
let a = opts.a || { e: 7, n: 8 };
({ t, e, n, s = 5 + 4, o, r } = a);
console.log(t, e, n, s, o, r);
}
let t, e, n;
test({a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 }});
test({});
}
expect: {
function e(e) {
let l, s, a;
let c = e.a || { e: 7, n: 8 };
({t: n, e: o, n: t, s: l = 9, o: s, r: a} = c);
console.log(n, o, t, l, s, a);
}
let n, o, t;
e({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
e({});
}
expect_stdout: [
"1 2 3 4 5 6",
"undefined 7 8 9 undefined undefined",
]
node_version: ">=6"
}
mangle_destructuring_assign_toplevel_false: {
options = {
toplevel: false,
evaluate: true,
unused: true,
}
mangle = {
toplevel: false,
}
beautify = {
ecma: 6
}
input: {
function test(opts) {
let s, o, r;
let a = opts.a || { e: 7, n: 8 };
({ t, e, n, s = 9, o, r } = a);
console.log(t, e, n, s, o, r);
}
let t, e, n;
test({a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 }});
test({});
}
expect: {
function test(o) {
let s, l, a;
let c = o.a || { e: 7, n: 8 };
({t, e, n, s = 9, o: l, r: a} = c);
console.log(t, e, n, s, l, a);
}
let t, e, n;
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
test({});
}
expect_stdout: [
"1 2 3 4 5 6",
"undefined 7 8 9 undefined undefined",
]
node_version: ">=6"
}
mangle_destructuring_decl_array: {
options = {
evaluate: true,
unused: true,
toplevel: true,
}
mangle = {
toplevel: true,
}
beautify = {
ecma: 6
}
input: {
var [, t, e, n, s, o = 2, r = [ 1 + 2 ]] = [ 9, 8, 7, 6 ];
console.log(t, e, n, s, o, r);
}
expect: {
var [, o, l, a, c, e = 2, g = [ 3 ]] = [ 9, 8, 7, 6 ];
console.log(o, l, a, c, e, g);
}
expect_stdout: "8 7 6 undefined 2 [ 3 ]"
node_version: ">=6"
}
anon_func_with_destructuring_args: {
options = {
evaluate: true,
unused: true,
toplevel: true,
}
mangle = {
toplevel: true,
}
beautify = {
ecma: 5,
}
input: {
(function({foo = 1 + 0, bar = 2}, [car = 3, far = 4]) {
console.log(foo, bar, car, far);
})({bar: 5 - 0}, [, 6]);
}
expect: {
(function({foo: o = 1, bar: n = 2}, [a = 3, b = 4]) {
console.log(o, n, a, b);
})({bar: 5}, [, 6]);
}
expect_stdout: "1 5 3 6"
node_version: ">=6"
}
arrow_func_with_destructuring_args: {
options = {
evaluate: true,
unused: true,
toplevel: true,
}
mangle = {
toplevel: true,
}
beautify = {
ecma: 5,
}
input: {
(({foo = 1 + 0, bar = 2}, [car = 3, far = 4]) => {
console.log(foo, bar, car, far);
})({bar: 5 - 0}, [, 6]);
}
expect: {
(({foo: o = 1, bar: a = 2}, [b = 3, l = 4]) => {
console.log(o, a, b, l);
})({bar: 5}, [, 6]);
}
expect_stdout: "1 5 3 6"
node_version: ">=6"
}
issue_2044_ecma_5: {
beautify = {
beautify: false,
ecma: 5,
}
input: {
({x : a = 1, y = 2 + b, z = 3 - c} = obj);
}
expect_exact: "({x:a=1,y:y=2+b,z:z=3-c}=obj);"
}
issue_2044_ecma_6: {
beautify = {
beautify: false,
ecma: 6,
}
input: {
({x : a = 1, y = 2 + b, z = 3 - c} = obj);
}
expect_exact: "({x:a=1,y=2+b,z=3-c}=obj);"
}
issue_2044_ecma_5_beautify: {
beautify = {
beautify: true,
ecma: 5,
}
input: {
({x : a = 1, y = 2 + b, z = 3 - c} = obj);
}
expect_exact: "({x: a = 1, y: y = 2 + b, z: z = 3 - c} = obj);"
}
issue_2044_ecma_6_beautify: {
beautify = {
beautify: true,
ecma: 6,
}
input: {
({x : a = 1, y = 2 + b, z = 3 - c} = obj);
}
expect_exact: "({x: a = 1, y = 2 + b, z = 3 - c} = obj);"
}
issue_2140: {
options = {
unused: true,
}
input: {
!function() {
var t = {};
console.log(([t.a] = [42])[0]);
}();
}
expect: {
!function() {
var t = {};
console.log(([t.a] = [42])[0]);
}();
}
expect_stdout: "42"
node_version: ">=6"
}

View File

@@ -0,0 +1,10 @@
class_directives_compression: {
input: {
class foo {
foo() {
"use strict";
}
}
}
expect_exact: "class foo{foo(){}}"
}

View File

@@ -164,6 +164,87 @@ used_var_in_catch: {
}
}
unused_block_decls_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
let x = 10;
const y = 10;
class Zee {};
}
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {}
}
}
}
used_block_decls_in_catch: {
options = { unused: true };
input: {
function foo() {
try {
foo();
} catch(ex) {
let x = 10;
const y = 10;
class Zee {};
}
console.log(x, y, Zee);
}
}
expect: {
function foo() {
try {
foo();
} catch(ex) {}
console.log(x, y, Zee);
}
}
}
unused_block_decls: {
options = { unused: true };
input: {
function foo() {
{
const x;
}
{
let y;
}
console.log(x, y);
}
}
expect: {
function foo() {
console.log(x, y);
}
}
}
unused_keep_harmony_destructuring: {
options = { unused: true };
input: {
function foo() {
var {x, y} = foo;
var a = foo;
}
}
expect: {
function foo() {
var {x, y} = foo;
}
}
}
keep_fnames: {
options = { unused: true, keep_fnames: true, unsafe: true };
input: {
@@ -632,7 +713,7 @@ iife: {
}
expect: {
function f() {
~function() {}(b);
b;
}
}
}
@@ -679,3 +760,669 @@ const_assign: {
}
}
}
issue_1539: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f() {
var a, b;
a = b = 42;
return a;
}
}
expect: {
function f() {
return 42;
}
}
}
vardef_value: {
options = {
keep_fnames: false,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g(){
return x();
}
var a = g();
return a(42);
}
}
expect: {
function f() {
var a = function(){
return x();
}();
return a(42);
}
}
}
assign_binding: {
options = {
cascade: true,
side_effects: true,
unused: true,
}
input: {
function f() {
var a;
a = f.g, a();
}
}
expect: {
function f() {
(0, f.g)();
}
}
}
assign_chain: {
options = {
unused: true,
}
input: {
function f() {
var a, b;
x = a = y = b = 42;
}
}
expect: {
function f() {
x = y = 42;
}
}
}
issue_1583: {
options = {
keep_fargs: true,
reduce_vars: true,
unused: true,
}
input: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
}
}
expect: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
}
}
}
issue_1656: {
options = {
toplevel: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
for(var a=0;;);
}
expect_exact: "for (;;) ;"
}
issue_1709: {
options = {
unused: true,
}
input: {
console.log(
function x() {
var x = 1;
return x;
}(),
function y() {
const y = 2;
return y;
}(),
function z() {
function z() {}
return z;
}()
);
}
expect: {
console.log(
function() {
var x = 1;
return x;
}(),
function() {
const y = 2;
return y;
}(),
function() {
function z() {}
return z;
}()
);
}
expect_stdout: true
}
issue_1715_1: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_2: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a = 2;
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_3: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
console;
} catch (a) {
var a = 2 + x();
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
console;
} catch (a) {
var a;
x();
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_4: {
options = {
unused: true,
}
input: {
var a = 1;
!function a() {
a++;
try {
x();
} catch (a) {
var a;
}
}();
console.log(a);
}
expect: {
var a = 1;
!function() {
a++;
try {
x();
} catch (a) {
var a;
}
}();
console.log(a);
}
expect_stdout: "1"
}
delete_assign_1: {
options = {
booleans: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
console.log(delete (a = undefined));
console.log(delete (a = void 0));
console.log(delete (a = Infinity));
console.log(delete (a = 1 / 0));
console.log(delete (a = NaN));
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((1 / 0, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_assign_2: {
options = {
booleans: true,
keep_infinity: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a;
console.log(delete (a = undefined));
console.log(delete (a = void 0));
console.log(delete (a = Infinity));
console.log(delete (a = 1 / 0));
console.log(delete (a = NaN));
console.log(delete (a = 0 / 0));
}
expect: {
console.log((void 0, !0));
console.log((void 0, !0));
console.log((Infinity, !0));
console.log((1 / 0, !0));
console.log((NaN, !0));
console.log((0 / 0, !0));
}
expect_stdout: true
}
drop_var: {
options = {
toplevel: true,
unused: true,
}
input: {
var a;
console.log(a, b);
var a = 1, b = 2;
console.log(a, b);
var a = 3;
console.log(a, b);
}
expect: {
console.log(a, b);
var a = 1, b = 2;
console.log(a, b);
a = 3;
console.log(a, b);
}
expect_stdout: [
"undefined undefined",
"1 2",
"3 2",
]
}
issue_1830_1: {
options = {
unused: true,
}
input: {
!function() {
L: for (var b = console.log(1); !1;) continue L;
}();
}
expect: {
!function() {
L: for (console.log(1); !1;) continue L;
}();
}
expect_stdout: "1"
}
issue_1830_2: {
options = {
unused: true,
}
input: {
!function() {
L: for (var a = 1, b = console.log(a); --a;) continue L;
}();
}
expect: {
!function() {
var a = 1;
L: for (console.log(a); --a;) continue L;
}();
}
expect_stdout: "1"
}
issue_1838: {
options = {
join_vars: true,
loops: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
function f() {
var b = a;
while (c);
}
}
expect_exact: [
"function f() {",
" for (a; c; ) ;",
"}",
]
}
var_catch_toplevel: {
options = {
conditionals: true,
negate_iife: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {
a--;
try {
a++;
} catch(a) {
if (a) var a;
var a = 10;
}
}
f();
}
expect: {
!function() {
a--;
try {
a++;
} catch(a) {
var a;
}
}();
}
}
reassign_const: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f() {
const a = 1;
a = 2;
return a;
}
console.log(f());
}
expect: {
function f() {
const a = 1;
return a = 2, a;
}
console.log(f());
}
expect_stdout: true
}
issue_1968: {
options = {
unused: true,
}
input: {
function f(c) {
var a;
if (c) {
let b;
return (a = 2) + (b = 3);
}
}
console.log(f(1));
}
expect: {
function f(c) {
if (c) {
let b;
return 2 + (b = 3);
}
}
console.log(f(1));
}
expect_stdout: "5"
node_version: ">=6"
}
issue_2063: {
options = {
unused: true,
}
input: {
var a;
var a;
}
expect: {
var a;
var a;
}
}
issue_2105: {
options = {
collapse_vars: true,
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
} );
});
}
expect: {
!void function() {
var quux = function() {
console.log("PASS");
};
return {
prop: function() {
console.log;
quux();
}
};
}().prop();
}
expect_stdout: "PASS"
}
issue_2136_1: {
options = {
inline: true,
unused: true,
}
input: {
!function(a, ...b) {
console.log(b);
}();
}
expect: {
!function(a, ...b) {
console.log(b);
}();
}
expect_stdout: "[]"
node_version: ">=6"
}
issue_2136_2: {
options = {
collapse_vars: true,
inline: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
console.log(x);
}
!function(a, ...b) {
f(b[0]);
}(1, 2, 3);
}
expect: {
function f(x) {
console.log(x);
}
f([2,3][0]);
}
expect_stdout: "2"
node_version: ">=6"
}
issue_2136_3: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function f(x) {
console.log(x);
}
!function(a, ...b) {
f(b[0]);
}(1, 2, 3);
}
expect: {
console.log(2);
}
expect_stdout: "2"
node_version: ">=6"
}
issue_2163: {
options = {
pure_funcs: [ "pure" ],
side_effects: true,
}
input: {
var c;
/*@__PURE__*/f(...a);
pure(b, ...c);
}
expect: {
var c;
a;
b;
}
}

View File

@@ -196,10 +196,11 @@ negative_zero: {
console.log(
-0,
0,
1 / (-0),
1 / (-0)
-1/0,
-1/0
);
}
expect_stdout: true
}
positive_zero: {
@@ -216,10 +217,105 @@ positive_zero: {
console.log(
0,
-0,
1 / (0),
1 / (0)
1/0,
1/0
);
}
expect_stdout: true
}
pow: {
options = { evaluate: true }
input: {
var a = 5 ** 3;
}
expect: {
var a = 125;
}
}
pow_sequence: {
options = {
evaluate: true
}
input: {
var a = 2 ** 3 ** 2;
}
expect: {
var a = 512;
}
}
pow_mixed: {
options = {
evaluate: true
}
input: {
var a = 5 + 2 ** 3 + 5;
var b = 5 * 3 ** 2;
var c = 5 ** 3 * 2;
var d = 5 ** +3;
}
expect: {
var a = 18;
var b = 45;
var c = 250;
var d = 125;
}
}
pow_with_right_side_evaluating_to_unary: {
options = {
evaluate: true
}
input: {
var a = (4 - 7) ** foo;
var b = ++bar ** 3;
var c = --baz ** 2;
}
expect_exact: "var a=(-3)**foo;var b=++bar**3;var c=--baz**2;"
}
pow_with_number_constants: {
options = {
evaluate: true
}
input: {
var a = 5 ** NaN;
/* NaN exponent results to NaN */
var b = 42 ** +0;
/* +0 exponent results to NaN */
var c = 42 ** -0;
/* -0 exponent results to NaN */
var d = NaN ** 1;
/* NaN with non-zero exponent is NaN */
var e = 2 ** Infinity;
/* abs(base) > 1 with Infinity as exponent is Infinity */
var f = 2 ** -Infinity;
/* abs(base) > 1 with -Infinity as exponent is +0 */
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
var m = 3 ** -10; // Result will be 0.000016935087808430286, which is too long
}
expect: {
var a = NaN;
var b = 1;
var c = 1;
var d = NaN;
var e = 1/0;
var f = 0;
var g = NaN;
var h = 1/0;
var i = -1/0;
var j = .125;
var k = .125;
var l = .25;
var m = 3 ** -10;
}
}
unsafe_constant: {
@@ -243,6 +339,7 @@ unsafe_constant: {
(void 0).a
);
}
expect_stdout: true
}
unsafe_object: {
@@ -266,6 +363,7 @@ unsafe_object: {
1..b + 1
);
}
expect_stdout: true
}
unsafe_object_nested: {
@@ -289,6 +387,7 @@ unsafe_object_nested: {
2
);
}
expect_stdout: true
}
unsafe_object_complex: {
@@ -312,6 +411,7 @@ unsafe_object_complex: {
2
);
}
expect_stdout: true
}
unsafe_object_repeated: {
@@ -335,6 +435,7 @@ unsafe_object_repeated: {
1..b + 1
);
}
expect_stdout: true
}
unsafe_object_accessor: {
@@ -384,6 +485,7 @@ unsafe_function: {
({a:{b:1},b:function(){}}).a.b + 1
);
}
expect_stdout: true
}
unsafe_integer_key: {
@@ -411,6 +513,7 @@ unsafe_integer_key: {
1["1"] + 1
);
}
expect_stdout: true
}
unsafe_integer_key_complex: {
@@ -438,6 +541,7 @@ unsafe_integer_key_complex: {
2
);
}
expect_stdout: true
}
unsafe_float_key: {
@@ -465,6 +569,7 @@ unsafe_float_key: {
1["3.14"] + 1
);
}
expect_stdout: true
}
unsafe_float_key_complex: {
@@ -492,6 +597,7 @@ unsafe_float_key_complex: {
2
);
}
expect_stdout: true
}
unsafe_array: {
@@ -527,6 +633,7 @@ unsafe_array: {
(void 0)[1] + 1
);
}
expect_stdout: true
}
unsafe_string: {
@@ -554,6 +661,7 @@ unsafe_string: {
"11"
);
}
expect_stdout: true
}
unsafe_array_bad_index: {
@@ -575,6 +683,7 @@ unsafe_array_bad_index: {
[1, 2, 3, 4][3.14] + 1
);
}
expect_stdout: true
}
unsafe_string_bad_index: {
@@ -596,6 +705,7 @@ unsafe_string_bad_index: {
"1234"[3.14] + 1
);
}
expect_stdout: true
}
unsafe_prototype_function: {
@@ -628,6 +738,7 @@ unsafe_prototype_function: {
call_args: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
}
input: {
@@ -640,10 +751,32 @@ call_args: {
expect: {
const a = 1;
console.log(1);
+function(a) {
return 1;
}(1);
+(1, 1);
}
expect_stdout: true
}
call_args_drop_param: {
options = {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_vars: true,
unused: true,
}
input: {
const a = 1;
console.log(a);
+function(a) {
return a;
}(a, b);
}
expect: {
const a = 1;
console.log(1);
+(b, 1);
}
expect_stdout: true
}
in_boolean_context: {
@@ -681,4 +814,351 @@ in_boolean_context: {
(foo(), !1)
);
}
expect_stdout: true
}
unsafe_charAt: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
"1234" + 1,
"1234".charAt(0) + 1,
"1234".charAt(6 - 5) + 1,
("12" + "34").charAt(0) + 1,
("12" + "34").charAt(6 - 5) + 1,
[1, 2, 3, 4].join("").charAt(0) + 1
);
}
expect: {
console.log(
"12341",
"11",
"21",
"11",
"21",
"11"
);
}
expect_stdout: true
}
unsafe_charAt_bad_index: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
"1234".charAt() + 1,
"1234".charAt("a") + 1,
"1234".charAt(3.14) + 1
);
}
expect: {
console.log(
"11",
"11",
"41"
);
}
expect_stdout: true
}
unsafe_charAt_noop: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
s.charAt(0),
"string".charAt(x),
(typeof x).charAt()
);
}
expect: {
console.log(
s.charAt(0),
"string".charAt(x),
(typeof x)[0]
);
}
}
issue_1649: {
options = {
evaluate: true,
}
input: {
console.log(-1 + -1);
}
expect: {
console.log(-2);
}
expect_stdout: "-2";
}
issue_1760_1: {
options = {
evaluate: true,
}
input: {
!function(a) {
try {
throw 0;
} catch (NaN) {
a = +"foo";
}
console.log(a);
}();
}
expect: {
!function(a) {
try {
throw 0;
} catch (NaN) {
a = 0 / 0;
}
console.log(a);
}();
}
expect_stdout: "NaN"
}
issue_1760_2: {
options = {
evaluate: true,
keep_infinity: true,
}
input: {
!function(a) {
try {
throw 0;
} catch (Infinity) {
a = 123456789 / 0;
}
console.log(a);
}();
}
expect: {
!function(a) {
try {
throw 0;
} catch (Infinity) {
a = 1 / 0;
}
console.log(a);
}();
}
expect_stdout: "Infinity"
}
delete_expr_1: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(delete undefined);
console.log(delete void 0);
console.log(delete Infinity);
console.log(delete (1 / 0));
console.log(delete NaN);
console.log(delete (0 / 0));
}
expect: {
console.log(delete undefined);
console.log((void 0, !0));
console.log(delete Infinity);
console.log((1 / 0, !0));
console.log(delete NaN);
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_expr_2: {
options = {
booleans: true,
evaluate: true,
keep_infinity: true,
}
input: {
console.log(delete undefined);
console.log(delete void 0);
console.log(delete Infinity);
console.log(delete (1 / 0));
console.log(delete NaN);
console.log(delete (0 / 0));
}
expect: {
console.log(delete undefined);
console.log((void 0, !0));
console.log(delete Infinity);
console.log((1 / 0, !0));
console.log(delete NaN);
console.log((0 / 0, !0));
}
expect_stdout: true
}
delete_binary_1: {
options = {
booleans: true,
evaluate: true,
side_effects: true,
}
input: {
console.log(delete (true && undefined));
console.log(delete (true && void 0));
console.log(delete (true && Infinity));
console.log(delete (true && (1 / 0)));
console.log(delete (true && NaN));
console.log(delete (true && (0 / 0)));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
delete_binary_2: {
options = {
booleans: true,
evaluate: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (false || undefined));
console.log(delete (false || void 0));
console.log(delete (false || Infinity));
console.log(delete (false || (1 / 0)));
console.log(delete (false || NaN));
console.log(delete (false || (0 / 0)));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
Infinity_NaN_undefined_LHS: {
beautify = {
beautify: true,
}
input: {
function f() {
Infinity = Infinity;
++Infinity;
Infinity--;
NaN *= NaN;
++NaN;
NaN--;
undefined |= undefined;
++undefined;
undefined--;
}
}
expect_exact: [
"function f() {",
" Infinity = 1 / 0;",
" ++Infinity;",
" Infinity--;",
" NaN *= NaN;",
" ++NaN;",
" NaN--;",
" undefined |= void 0;",
" ++undefined;",
" undefined--;",
"}",
]
}
issue_1964_1: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_regexp: false,
unused: true,
}
input: {
function f() {
var long_variable_name = /\s/;
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
var long_variable_name = /\s/;
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect_stdout: "b"
}
issue_1964_2: {
options = {
evaluate: true,
reduce_vars: true,
unsafe_regexp: true,
unused: true,
}
input: {
function f() {
var long_variable_name = /\s/;
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
return "a b c".split(/\s/)[1];
}
console.log(f());
}
expect_stdout: "b"
}
array_slice_index: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log([1,2,3].slice(1)[1]);
}
expect: {
console.log(3);
}
expect_stdout: "3"
}
string_charCodeAt: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log("foo".charCodeAt("bar".length));
}
expect: {
console.log(NaN);
}
expect_stdout: "NaN"
}

View File

@@ -0,0 +1,28 @@
expand_arguments: {
input: {
func(a, ...rest);
func(...all);
}
expect_exact: "func(a,...rest);func(...all);"
}
expand_expression_arguments: {
input: {
f(...a.b);
f(...a.b());
f(...(a));
f(...(a.b));
f(...a[i]);
}
expect_exact: "f(...a.b);f(...a.b());f(...a);f(...a.b);f(...a[i]);"
}
expand_parameters: {
input: {
(function (a, ...b){});
(function (...args){});
}
expect_exact: "(function(a,...b){});(function(...args){});"
}

228
test/compress/export.js Normal file
View File

@@ -0,0 +1,228 @@
issue_2038_1: {
options = {
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
export var V = 1;
export let L = 2;
export const C = 3;
}
expect: {
export var V = 1;
export let L = 2;
export const C = 3;
}
}
issue_2038_2: {
options = {
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
let LET = 1;
const CONST = 2;
var VAR = 3;
export { LET, CONST, VAR };
}
expect: {
let t = 1;
const e = 2;
var o = 3;
export { t as LET, e as CONST, o as VAR };
}
}
issue_2126: {
mangle = {
toplevel: true,
}
input: {
import { foo as bar, cat as dog } from "stuff";
console.log(bar, dog);
export { bar as qux };
export { dog };
}
expect: {
import { foo as o, cat as s } from "stuff";
console.log(o, s);
export { o as qux };
export { s as dog };
}
}
beautify: {
beautify = {
beautify: true,
}
input: {
export { A as B, C as D };
}
expect_exact: "export { A as B, C as D };"
}
issue_2131: {
options = {
toplevel: true,
unused: true,
}
input: {
function no() {
console.log(42);
}
function go() {
console.log(42);
}
var X = 1, Y = 2;
export function main() {
go(X);
};
}
expect: {
function go() {
console.log(42);
}
var X = 1;
export function main() {
go(X);
};
}
}
issue_2129: {
mangle = {
toplevel: true,
}
input: {
export const { keys } = Object;
}
expect: {
export const { keys } = Object;
}
}
async_func: {
options = {
keep_fargs: false,
unused: true,
}
input: {
export async function Foo(x){};
}
expect: {
export async function Foo(){};
}
}
issue_2134_1: {
options = {
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
export function Foo(x){};
Foo.prototype = {};
}
expect: {
export function Foo(){};
Foo.prototype = {};
}
}
issue_2134_2: {
options = {
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
export async function Foo(x){};
Foo.prototype = {};
}
expect: {
export async function Foo(){};
Foo.prototype = {};
}
}
redirection: {
mangle = {
toplevel: true,
}
input: {
let foo = 1, bar = 2;
export { foo as delete };
export { bar as default };
export { foo as var } from "module.js";
}
expect: {
let e = 1, o = 2;
export { e as delete };
export { o as default };
export { foo as var } from "module.js";
}
}
keyword_invalid_1: {
input: {
export { default };
}
expect: {
export { default };
}
}
keyword_invalid_2: {
input: {
export { default as Alias };
}
expect: {
export { default as Alias };
}
}
keyword_invalid_3: {
input: {
export { default as default };
}
expect: {
export { default as default };
}
}
keyword_valid_1: {
input: {
export { default } from "module.js";
}
expect: {
export { default } from "module.js";
}
}
keyword_valid_2: {
input: {
export { default as Alias } from "module.js";
}
expect: {
export { default as Alias } from "module.js";
}
}
keyword_valid_3: {
input: {
export { default as default } from "module.js";
}
expect: {
export { default as default } from "module.js";
}
}

View File

@@ -0,0 +1,52 @@
pow: {
input: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
expect: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
}
pow_with_number_constants: {
input: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** Infinity;
var f = 2 ** -Infinity;
}
expect: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** (1/0);
var f = 2 ** (-1/0);
}
}
pow_with_parentheses: {
input: {
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
}
expect_exact: "var g=(-7)**.5;var h=2324334**34343443;var i=(-2324334)**34343443;var j=2**-3;var k=2**-3;var l=2**(5-7);"
}
pow_with_unary_between_brackets: {
input: {
var a = (-(+5)) ** 3;
}
expect: {
var a = (-+5)**3;
}
}

View File

@@ -6,3 +6,507 @@ non_ascii_function_identifier_name: {
}
expect_exact: "function fooλ(δλ){}function λ(δλ){}(function λ(δλ){})();"
}
iifes_returning_constants_keep_fargs_true: {
options = {
keep_fargs : true,
side_effects : true,
evaluate : true,
unused : true,
dead_code : true,
conditionals : true,
comparisons : true,
booleans : true,
if_return : true,
join_vars : true,
reduce_vars : true,
cascade : true,
inline : true,
}
input: {
(function(){ return -1.23; }());
console.log( function foo(){ return "okay"; }() );
console.log( function foo(x, y, z){ return 123; }() );
console.log( function(x, y, z){ return z; }() );
console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) );
console.log( function(x, y){ return x * y; }(2, 3) );
console.log( function(x, y){ return x * y; }(2, 3, a(), b()) );
}
expect: {
console.log("okay");
console.log(123);
console.log(void 0);
console.log(2);
console.log(6);
console.log((a(), b(), 6));
}
expect_stdout: true
}
iifes_returning_constants_keep_fargs_false: {
options = {
keep_fargs : false,
side_effects : true,
evaluate : true,
unused : true,
dead_code : true,
conditionals : true,
comparisons : true,
booleans : true,
if_return : true,
join_vars : true,
reduce_vars : true,
cascade : true,
inline : true,
}
input: {
(function(){ return -1.23; }());
console.log( function foo(){ return "okay"; }() );
console.log( function foo(x, y, z){ return 123; }() );
console.log( function(x, y, z){ return z; }() );
console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) );
console.log( function(x, y){ return x * y; }(2, 3) );
console.log( function(x, y){ return x * y; }(2, 3, a(), b()) );
}
expect: {
console.log("okay");
console.log(123);
console.log(void 0);
console.log(2);
console.log(6);
console.log((a(), b(), 6));
}
expect_stdout: true
}
issue_485_crashing_1530: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
inline: true,
}
input: {
(function(a) {
if (true) return;
var b = 42;
})(this);
}
expect: {
this, void 0;
}
}
issue_1841_1: {
options = {
keep_fargs: false,
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
var b = 10;
!function(arg) {
for (var key in "hi")
var n = arg.baz, n = [ b = 42 ];
}(--b);
console.log(b);
}
expect: {
var b = 10;
!function() {
for (var key in "hi")
b = 42;
}(--b);
console.log(b);
}
expect_exact: "42"
}
issue_1841_2: {
options = {
keep_fargs: false,
pure_getters: false,
reduce_vars: true,
unused: true,
}
input: {
var b = 10;
!function(arg) {
for (var key in "hi")
var n = arg.baz, n = [ b = 42 ];
}(--b);
console.log(b);
}
expect: {
var b = 10;
!function(arg) {
for (var key in "hi")
arg.baz, b = 42;
}(--b);
console.log(b);
}
expect_exact: "42"
}
function_returning_constant_literal: {
options = {
reduce_vars: true,
unsafe: true,
toplevel: true,
evaluate: true,
cascade: true,
unused: true,
inline: true,
}
input: {
function greeter() {
return { message: 'Hello there' };
}
var greeting = greeter();
console.log(greeting.message);
}
expect: {
console.log("Hello there");
}
expect_stdout: "Hello there"
}
hoist_funs: {
options = {
hoist_funs: true,
}
input: {
console.log(1, typeof f, typeof g);
if (console.log(2, typeof f, typeof g))
console.log(3, typeof f, typeof g);
else {
console.log(4, typeof f, typeof g);
function f() {}
console.log(5, typeof f, typeof g);
}
function g() {}
console.log(6, typeof f, typeof g);
}
expect: {
function g() {}
console.log(1, typeof f, typeof g);
if (console.log(2, typeof f, typeof g))
console.log(3, typeof f, typeof g);
else {
console.log(4, typeof f, typeof g);
function f() {}
console.log(5, typeof f, typeof g);
}
console.log(6, typeof f, typeof g);
}
expect_stdout: [
"1 'undefined' 'function'",
"2 'undefined' 'function'",
"4 'function' 'function'",
"5 'function' 'function'",
"6 'function' 'function'",
]
node_version: ">=6"
}
hoist_funs_strict: {
options = {
hoist_funs: true,
}
input: {
"use strict";
console.log(1, typeof f, typeof g);
if (console.log(2, typeof f, typeof g))
console.log(3, typeof f, typeof g);
else {
console.log(4, typeof f, typeof g);
function f() {}
console.log(5, typeof f, typeof g);
}
function g() {}
console.log(6, typeof f, typeof g);
}
expect: {
"use strict";
function g() {}
console.log(1, typeof f, typeof g);
if (console.log(2, typeof f, typeof g))
console.log(3, typeof f, typeof g);
else {
console.log(4, typeof f, typeof g);
function f() {}
console.log(5, typeof f, typeof g);
}
console.log(6, typeof f, typeof g);
}
expect_stdout: [
"1 'undefined' 'function'",
"2 'undefined' 'function'",
"4 'function' 'function'",
"5 'function' 'function'",
"6 'undefined' 'function'",
]
node_version: ">=4"
}
issue_203: {
options = {
keep_fargs: false,
side_effects: true,
unsafe_Func: true,
unused: true,
}
input: {
var m = {};
var fn = Function("require", "module", "exports", "module.exports = 42;");
fn(null, m, m.exports);
console.log(m.exports);
}
expect: {
var m = {};
var fn = Function("n,o", "o.exports=42");
fn(null, m, m.exports);
console.log(m.exports);
}
expect_stdout: "42"
}
no_webkit: {
beautify = {
webkit: false,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log(function(){1+1}.a=1);"
expect_stdout: "1"
}
webkit: {
beautify = {
webkit: true,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log((function(){1+1}).a=1);"
expect_stdout: "1"
}
issue_2084: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
!function() {
!function(c) {
c = 1 + c;
var c = 0;
function f14(a_1) {
if (c = 1 + c, 0 !== 23..toString())
c = 1 + c, a_1 && (a_1[0] = 0);
}
f14();
}(-1);
}();
console.log(c);
}
expect: {
var c = 0;
!function(c) {
c = 1 + c,
c = 1 + (c = 0),
0 !== 23..toString() && (c = 1 + c);
}(-1),
console.log(c);
}
expect_stdout: "0"
}
issue_2097: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
try {
throw 0;
} catch (e) {
console.log(arguments[0]);
}
}
f(1);
}
expect: {
!function() {
try {
throw 0;
} catch (e) {
console.log(arguments[0]);
}
}(1);
}
expect_stdout: "1"
}
issue_2101: {
options = {
inline: true,
}
input: {
a = {};
console.log(function() {
return function() {
return this.a;
}();
}() === function() {
return a;
}());
}
expect: {
a = {};
console.log(function() {
return this.a;
}() === a);
}
expect_stdout: "true"
}
inner_ref: {
options = {
inline: true,
unused: true,
}
input: {
console.log(function(a) {
return function() {
return a;
}();
}(1), function(a) {
return function(a) {
return a;
}();
}(2));
}
expect: {
console.log(function(a) {
return a;
}(1), function(a) {
return a;
}());
}
expect_stdout: "1 undefined"
}
issue_2107: {
options = {
cascade: true,
collapse_vars: true,
inline: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
!function() {
c++;
}(c++ + new function() {
this.a = 0;
var a = (c = c + 1) + (c = 1 + c);
return c++ + a;
}());
console.log(c);
}
expect: {
var c = 0;
c++, new function() {
this.a = 0, c = 1 + (c += 1), c++;
}(), c++, console.log(c);
}
expect_stdout: "5"
}
issue_2114_1: {
options = {
collapse_vars: true,
if_return: true,
inline: true,
keep_fargs: false,
side_effects: true,
unused: true,
}
input: {
var c = 0;
!function(a) {
a = 0;
}([ {
0: c = c + 1,
length: c = 1 + c
}, typeof void function a() {
var b = function f1(a) {
}(b && (b.b += (c = c + 1, 0)));
}() ]);
console.log(c);
}
expect: {
var c = 0;
!function() {
0;
}((c += 1, c = 1 + c, function() {
var b = void (b && (b.b += (c += 1, 0)));
}()));
console.log(c);
}
expect_stdout: "2"
}
issue_2114_2: {
options = {
collapse_vars: true,
if_return: true,
inline: true,
keep_fargs: false,
passes: 2,
side_effects: true,
unused: true,
}
input: {
var c = 0;
!function(a) {
a = 0;
}([ {
0: c = c + 1,
length: c = 1 + c
}, typeof void function a() {
var b = function f1(a) {
}(b && (b.b += (c = c + 1, 0)));
}() ]);
console.log(c);
}
expect: {
var c = 0;
c = 1 + (c += 1), function() {
var b = void (b && (b.b += (c += 1, 0)));
}();
console.log(c);
}
expect_stdout: "2"
}

View File

@@ -145,3 +145,53 @@ mixed: {
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
]
}
issue_1801: {
options = {
booleans: true,
global_defs: {
"CONFIG.FOO.BAR": true,
},
}
input: {
console.log(CONFIG.FOO.BAR);
}
expect: {
console.log(!0);
}
}
issue_1986: {
options = {
global_defs: {
"@alert": "console.log",
},
}
input: {
alert(42);
}
expect: {
console.log(42);
}
}
issue_2167: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
global_defs: {
"@isDevMode": "function(){}",
},
side_effects: true,
}
input: {
if (isDevMode()) {
greetOverlord();
}
doWork();
}
expect: {
doWork();
}
}

697
test/compress/harmony.js Normal file
View File

@@ -0,0 +1,697 @@
arrow_function_parens: {
input: {
something && (() => {});
}
expect_exact: "something&&(()=>{});"
}
arrow_function_parens_2: {
input: {
(() => null)();
}
expect_exact: "(()=>null)();"
}
typeof_arrow_functions: {
options = {
evaluate: true
}
input: {
var foo = typeof (x => null);
console.log(foo);
}
expect_exact: "var foo=\"function\";console.log(foo);"
expect_stdout: "function"
node_version: ">=4"
}
classes: {
input: {
class SomeClass {
constructor() {
};
foo() {};
};
class NoSemi {
constructor(...args) {
}
foo() {}
};
class ChildClass extends SomeClass {};
var asExpression = class AsExpression {};
var nameless = class {};
}
expect_exact: "class SomeClass{constructor(){}foo(){}}class NoSemi{constructor(...args){}foo(){}}class ChildClass extends SomeClass{}var asExpression=class AsExpression{};var nameless=class{};"
}
class_statics: {
input: {
x = class {
static staticMethod() {}
static get foo() {}
static set bar() {}
static() { /* "static" can be a method name! */ }
get() { /* "get" can be a method name! */ }
set() { /* "set" can be a method name! */ }
}
}
expect_exact: "x=class{static staticMethod(){}static get foo(){}static set bar(){}static(){}get(){}set(){}};"
}
class_name_can_be_mangled: {
mangle = { };
input: {
function x() {
class Foo {
}
var class1 = Foo;
var class2 = class Bar {};
}
}
expect: {
function x() {
class a { }
var s = a;
var c = class a {};
}
}
}
class_name_can_be_preserved: {
mangle = {
keep_classnames: true
}
input: {
function x() {
(class Baz { });
class Foo {};
}
}
expect: {
function x() {
(class Baz { });
class Foo {};
}
}
}
classes_can_have_generators: {
input: {
class Foo {
*bar() {}
static *baz() {}
}
}
expect: {
class Foo {
*bar() {}
static *baz() {}
}
}
}
classes_can_have_computed_generators: {
input: {
class C4 {
*['constructor']() {}
}
}
expect: {
class C4 {
*['constructor']() {}
}
}
}
classes_can_have_computed_static: {
input: {
class C4 {
static ['constructor']() {}
}
}
expect: {
class C4 {
static ['constructor']() {}
}
}
}
class_methods_and_getters_with_keep_quoted_props_enabled: {
beautify = {
quote_style: 3,
keep_quoted_props: true,
}
input: {
class clss {
a() {}
"b"() {}
get c() { return "c"}
get "d"() { return "d"}
set e(a) { doSomething(a); }
set 'f'(a) { doSomething(b); }
static g() {}
static "h"() {}
}
}
expect_exact: 'class clss{a(){}"b"(){}get c(){return"c"}get"d"(){return"d"}set e(a){doSomething(a)}set\'f\'(a){doSomething(b)}static g(){}static"h"(){}}'
}
classes_with_expression_as_expand: {
input: {
class D extends (calls++, C) {}
}
expect_exact: "class D extends(calls++,C){}"
}
new_target: {
input: {
new.target;
new.target.name;
}
expect_exact: "new.target;new.target.name;"
}
number_literals: {
input: {
0b1001;
0B1001;
0o11;
0O11;
}
expect: {
9;
9;
9;
9;
}
}
import_statement: {
input: {
import "mod-name";
import Foo from "bar";
import { Bar, Baz } from 'lel';
import Bar, { Foo } from 'lel';
import { Bar as kex, Baz as food } from 'lel';
}
expect_exact: 'import"mod-name";import Foo from"bar";import{Bar,Baz}from"lel";import Bar,{Foo}from"lel";import{Bar as kex,Baz as food}from"lel";'
}
import_all_statement: {
input: {
import * from 'lel';
import * as Lel from 'lel';
}
expect_exact: 'import*from"lel";import*as Lel from"lel";'
}
export_statement: {
options = {
evaluate: true,
}
input: {
export default 1 + 2;
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 foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};"
}
export_default_object_expression: {
options = {
evaluate: true,
}
input: {
export default {
foo: 1 + 2,
bar() { return 4; },
get baz() { return this.foo; },
};
}
expect_exact: "export default{foo:3,bar(){return 4},get baz(){return this.foo}};"
}
export_default_array: {
options = {
evaluate: true,
}
input: {
export default [ 1 + 2, foo ];
}
expect_exact: "export default[3,foo];"
}
export_default_anon_function: {
options = {
evaluate: true,
}
input: {
export default function(){
console.log(1 + 2);
}
}
expect_exact: "export default function(){console.log(3)};"
}
export_default_anon_class: {
options = {
evaluate: true,
}
input: {
export default class {
foo() { console.log(1 + 2); }
}
}
expect_exact: "export default class{foo(){console.log(3)}};"
}
export_module_statement: {
input: {
export * from "a.js";
export {A} from "a.js";
export {A, B} from "a.js";
export {C};
}
expect_exact: 'export*from"a.js";export{A}from"a.js";export{A,B}from"a.js";export{C};'
}
import_statement_mangling: {
mangle = { toplevel: true };
input: {
import Foo from "foo";
import Bar, {Food} from "lel";
import {What as Whatever} from "lel";
Foo();
Bar();
Food();
Whatever();
}
expect: {
import o from "foo";
import m, {Food as r} from "lel";
import {What as f} from "lel";
o();
m();
r();
f();
}
}
export_statement_mangling: {
mangle = { };
input: {
export var foo = 6;
export function bar() { }
export class Baz { }
bar(foo, Baz)
}
expect: {
export var foo = 6;
export function bar() { }
export class Baz { }
bar(foo, Baz)
}
}
// https://github.com/mishoo/UglifyJS2/issues/1021
regression_for_of_const: {
input: {
for (const x of y) {}
for (const x in y) {}
}
expect: {
for (const x of y);for (const x in y);
}
}
// Fabio: My patches accidentally caused a crash whenever
// there's an extraneous set of parens around an object.
regression_cannot_destructure: {
input: {
var x = ({ x : 3 });
x(({ x: 3 }));
}
expect_exact: "var x={x:3};x({x:3});";
}
regression_cannot_use_of: {
input: {
function of() {
}
var of = "is a valid variable name";
of = { of: "is ok" };
x.of;
of: foo()
}
expect: {
function of(){}
var of="is a valid variable name";
of={of:"is ok"};
x.of;
foo(); /* Label statement missing? No prob. */
}
}
fat_arrow_as_param: {
input: {
foo(x => x);
foo(x => x, y => y);
foo(x => (x, x));
foo(x => (x, x), y => (y, y));
}
expect_exact: "foo(x=>x);foo(x=>x,y=>y);foo(x=>(x,x));foo(x=>(x,x),y=>(y,y));"
}
default_assign: {
options = {
keep_fargs: false,
unused: true,
}
input: {
function f(a, b = 3) {
console.log(a);
}
g = ([[] = 123]) => {};
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
function i([[x, y, z] = [4, 5, 6]] = []) {
console.log(b);
};
}
expect: {
function f(a) {
console.log(a);
}
g = ([[] = 123]) => {};
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
function i([[x, y, z] = [4, 5, 6]] = []) {
console.log(b);
};
}
}
expansion: {
options = {
keep_fargs: false,
unused: true,
}
input: {
function f(a, ...b) {
console.log(a);
}
}
expect: {
function f(a) {
console.log(a);
}
}
}
issue_1613: {
mangle = { toplevel: true };
input: {
const name = 1;
const foo = {
name
};
}
expect_exact: "const n=1;const c={name:n};"
}
format_methods: {
beautify = {
beautify: true,
}
input: {
class A extends B {constructor(a){x()} static s(b,c){y()} run(d,e,f){z()}}
}
expect_exact: [
"class A extends B {",
" constructor(a) {",
" x();",
" }",
" static s(b, c) {",
" y();",
" }",
" run(d, e, f) {",
" z();",
" }",
"}",
]
}
issue_1898: {
options = {
}
mangle = {
}
input: {
class Foo {
bar() {
for (const x of [ 6, 5 ]) {
for (let y of [ 4, 3 ]) {
for (var z of [ 2, 1 ]) {
console.log(x, y, z);
}
}
}
}
}
new Foo().bar();
}
expect: {
class Foo {
bar() {
for (const f of [ 6, 5 ])
for (let r of [ 4, 3 ])
for (var o of [ 2, 1 ])
console.log(f, r, o);
}
}
new Foo().bar();
}
}
issue_1753: {
mangle = { safari10: true };
input: {
class SomeClass {
constructor(props) {
let pickedSets = [];
for (let i = 0; i < 6; i++) {
pickedSets.push({
mainDrawNumbers: [],
extraDrawNumbers: []
});
}
}
}
}
expect: {
class SomeClass {
constructor(r) {
let s = [];
for (let a = 0; a < 6; a++)
s.push({
mainDrawNumbers: [],
extraDrawNumbers: []
});
}
}
}
}
issue_1753_disable: {
mangle = { safari10: false }
input: {
class SomeClass {
constructor(props) {
let pickedSets = [];
for (let i = 0; i < 6; i++) {
pickedSets.push({
mainDrawNumbers: [],
extraDrawNumbers: []
});
}
}
}
}
expect: {
class SomeClass {
constructor(r) {
let s = [];
for (let r = 0; r < 6; r++)
s.push({
mainDrawNumbers: [],
extraDrawNumbers: []
});
}
}
}
}
class_extends: {
options = {
evaluate: true,
}
input: {
function f() {
class foo extends bar {}
class pro extends some.prop {}
class arr extends stuff[1 - 1] {}
class bin extends (a || b) {}
class seq extends (a, b) {}
class ter extends (a ? b : c) {}
class uni extends (!0) {}
}
}
expect_exact: "function f(){class foo extends bar{}class pro extends some.prop{}class arr extends stuff[0]{}class bin extends(a||b){}class seq extends(a,b){}class ter extends(a?b:c){}class uni extends(!0){}}"
}
class_extends_class: {
options = {
}
input: {
class anon extends class {} {}
class named extends class base {} {}
}
expect_exact: "class anon extends class{}{}class named extends class base{}{}"
}
class_extends_function: {
options = {
}
input: {
class anon extends function(){} {}
class named extends function base(){} {}
}
expect_exact: "class anon extends function(){}{}class named extends function base(){}{}"
}
class_extends_regex: {
options = {
}
input: {
function f() {
class rx1 extends (/rx/) {}
// class rx2 extends /rx/ {} // FIXME - parse error
}
}
expect_exact: "function f(){class rx1 extends(/rx/){}}"
}
issue_2028: {
options = {
side_effects: true,
}
input: {
var a = {};
(function(x) {
x.X = function() {
return X;
};
class X {
static hello() {
console.log("hello");
}
}
}(a));
a.X().hello();
}
expect: {
var a = {};
(function(x) {
x.X = function() {
return X;
};
class X {
static hello() {
console.log("hello");
}
}
}(a));
a.X().hello();
}
expect_stdout: "hello"
node_version: ">=6"
}
class_expression_statement: {
options = {
toplevel: false,
side_effects: false,
unused: false,
}
input: {
(class {});
(class NamedClassExpr {});
let expr = (class AnotherClassExpr {});
class C {}
}
expect_exact: "(class{});(class NamedClassExpr{});let expr=class AnotherClassExpr{};class C{}"
}
class_expression_statement_unused: {
options = {
toplevel: false,
side_effects: true,
unused: true,
}
input: {
(class {});
(class NamedClassExpr {});
let expr = (class AnotherClassExpr {});
class C {}
}
expect_exact: "let expr=class{};class C{}"
}
class_expression_statement_unused_toplevel: {
options = {
toplevel: true,
side_effects: true,
unused: true,
}
input: {
(class {});
(class NamedClassExpr {});
let expr = (class AnotherClassExpr {});
class C {}
}
expect_exact: ""
}
export_default_function_decl: {
options = {
toplevel: true,
passes: 3,
unused: true,
}
input: {
// do not drop "unused" exports
export default function Foo() {};
export function Far() {};
}
expect_exact: "export default function Foo(){};export function Far(){};"
}
export_default_class_decl: {
options = {
toplevel: true,
passes: 3,
unused: true,
}
input: {
// do not drop "unused" exports
export default class Car {};
export class Cab {};
}
expect_exact: "export default class Car{};export class Cab{};"
}

85
test/compress/hoist.js Normal file
View File

@@ -0,0 +1,85 @@
hoist_vars: {
options = {
hoist_vars: true
}
input: {
function a() {
bar();
var var1;
var var2;
}
function b(anArg) {
bar();
var var1;
var anArg;
}
}
expect: {
function a() {
var var1, var2; // Vars go up and are joined
bar();
}
function b(anArg) {
var var1;
bar();
// But vars named like arguments go away!
}
}
}
hoist_funs: {
options = {
hoist_funs: true
}
input: {
function a() {
bar();
function foo() {}
}
}
expect: {
function a() {
function foo() {} // Funs go up
bar();
}
}
}
hoist_no_destructurings: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
function a([anArg]) {
bar();
var var1;
var anArg; // Because anArg is already declared, this goes away!
}
}
expect: {
function a([anArg]) {
var var1;
bar();
}
}
}
dont_hoist_var_destructurings: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
function x() {
// If foo is null or undefined, this should be an exception
var {x,y} = foo;
}
}
expect: {
function x() {
var {x,y} = foo;
}
}
}

View File

@@ -47,25 +47,18 @@ html_comment_in_greater_than_or_equal: {
expect_exact: "function f(a,b){return a-- >=b}";
}
html_comment_in_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>= b; }
}
expect_exact: "function f(a,b){return a-- >>=b}";
}
html_comment_in_zero_fill_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>>= b; }
}
expect_exact: "function f(a,b){return a-- >>>=b}";
}
html_comment_in_string_literal: {
input: {
function f() { return "<!--HTML-->comment in<!--string literal-->"; }
}
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
}
html_comment_after_multiline_comment: {
input: {
var foo; /*
*/--> var bar;
var foobar;
}
expect_exact: "var foo;var foobar;"
}

View File

@@ -302,3 +302,85 @@ issue_1437_conditionals: {
}
}
}
issue_512: {
options = {
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
}
input: {
function a() {
if (b()) {
c();
return;
}
throw e;
}
}
expect: {
function a() {
if (!b()) throw e;
c();
}
}
}
issue_1317: {
options = {
if_return: true,
}
input: {
!function(a) {
if (a) return;
let b = 1;
function g() {
return b;
}
console.log(g());
}();
}
expect: {
!function(a) {
if (a) return;
let b = 1;
function g() {
return b;
}
console.log(g());
}();
}
expect_stdout: "1"
node_version: ">=6"
}
issue_1317_strict: {
options = {
if_return: true,
}
input: {
"use strict";
!function(a) {
if (a) return;
let b = 1;
function g() {
return b;
}
console.log(g());
}();
}
expect: {
"use strict";
!function(a) {
if (a) return;
let b = 1;
function g() {
return b;
}
console.log(g());
}();
}
expect_stdout: "1"
node_version: ">=4"
}

View File

@@ -0,0 +1,8 @@
parenthesis_strings_in_parenthesis: {
input: {
var foo = ('(');
a(')');
}
expect_exact: 'var foo="(";a(")");'
}

View File

@@ -39,7 +39,7 @@ non_hoisted_function_after_return_2a: {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
function foo(x) {
@@ -75,7 +75,7 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]"
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
]
}
@@ -114,8 +114,139 @@ non_hoisted_function_after_return_2b: {
"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 unused variable b [test/compress/issue-1034.js:95,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:97,16]"
]
}
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
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar();
not_called1();
} else {
return baz();
not_called2();
}
function bar() { return 7; }
return not_reached;
function UnusedFunction() {}
function baz() { return 8; }
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return x ? bar() : baz();
function bar() { return 7 }
function baz() { return 8 }
}
console.log(foo(0), foo(1));
}
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]"
]
}
non_hoisted_function_after_return_2a_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar(1);
var a = not_called(1);
} else {
return bar(2);
var b = not_called(2);
}
var c = bar(3);
function bar(x) { return 7 - x; }
function nope() {}
return b || c;
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return bar(x ? 1 : 2);
function bar(x) {
return 7 - x;
}
}
console.log(foo(0), foo(1));
}
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]",
]
}
non_hoisted_function_after_return_2b_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar(1);
} else {
return bar(2);
var b;
}
var c = bar(3);
function bar(x) {
return 7 - x;
}
return b || c;
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return bar(x ? 1 : 2);
function bar(x) { return 7 - x; }
}
console.log(foo(0), foo(1));
}
expect_stdout: "5 6"
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
]
}

View File

@@ -0,0 +1,30 @@
issue_1043: {
options = {
side_effects: true
};
input: {
function* range(start = 0, end = null, step = 1) {
if (end == null) {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
yield i;
}
}
}
expect: {
function* range(start = 0, end = null, step = 1) {
if (null == end) {
end = start;
start = 0;
}
for (let i = start; i < end; i += step)
yield i;
}
}
}

View File

@@ -0,0 +1,9 @@
issue_1044: {
options = { evaluate: true, conditionals: true };
input: {
const mixed = Base ? class extends Base {} : class {}
}
expect: {
const mixed = Base ? class extends Base {} : class {}
}
}

View File

@@ -1,90 +1,91 @@
multiple_functions: {
options = { if_return: true, hoist_funs: false };
options = {
hoist_funs: false,
if_return: true,
}
input: {
( function() {
if ( !window ) {
return;
}
function f() {}
function g() {}
} )();
}
expect: {
( function() {
function f() {}
function g() {}
// NOTE: other compression steps will reduce this
// down to just `window`.
if ( window );
function f() {}
function g() {}
} )();
}
}
single_function: {
options = { if_return: true, hoist_funs: false };
options = {
hoist_funs: false,
if_return: true,
}
input: {
( function() {
if ( !window ) {
return;
}
function f() {}
} )();
}
expect: {
( function() {
function f() {}
if ( window );
function f() {}
} )();
}
}
deeply_nested: {
options = { if_return: true, hoist_funs: false };
options = {
hoist_funs: false,
if_return: true,
}
input: {
( function() {
if ( !window ) {
return;
}
function f() {}
function g() {}
if ( !document ) {
return;
}
function h() {}
} )();
}
expect: {
( function() {
function f() {}
function g() {}
function h() {}
// NOTE: other compression steps will reduce this
// down to just `window`.
if ( window )
if (document);
function f() {}
function g() {}
function h() {}
} )();
}
}
not_hoisted_when_already_nested: {
options = { if_return: true, hoist_funs: false };
options = {
hoist_funs: false,
if_return: true,
}
input: {
( function() {
if ( !window ) {
return;
}
if ( foo ) function f() {}
} )();
}
expect: {
@@ -94,3 +95,69 @@ not_hoisted_when_already_nested: {
} )();
}
}
defun_if_return: {
options = {
hoist_funs: false,
if_return: true,
}
input: {
function e() {
function f() {}
if (!window) return;
else function g() {}
function h() {}
}
}
expect: {
function e() {
function f() {}
if (window) function g() {}
function h() {}
}
}
}
defun_hoist_funs: {
options = {
hoist_funs: true,
if_return: true,
}
input: {
function e() {
function f() {}
if (!window) return;
else function g() {}
function h() {}
}
}
expect: {
function e() {
function f() {}
function h() {}
if (window) function g() {}
}
}
}
defun_else_if_return: {
options = {
hoist_funs: false,
if_return: true,
}
input: {
function e() {
function f() {}
if (window) function g() {}
else return;
function h() {}
}
}
expect: {
function e() {
function f() {}
if (window) function g() {}
function h() {}
}
}
}

View File

@@ -193,13 +193,15 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
cascade: true,
side_effects: true,
sequences: false,
keep_infinity: false,
}
input: {
var f = console.log;
var o = {
undefined : 3,
NaN : 4,
Infinity : 5,
}
};
if (o) {
f(undefined, void 0);
f(NaN, 0/0);
@@ -216,25 +218,88 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
}
}
expect: {
var o = {
var f = console.log, o = {
undefined : 3,
NaN : 4,
Infinity : 5
}
};
if (o) {
f(void 0, void 0);
f(NaN, NaN);
f(1/0, 1/0);
f(-(1/0), -(1/0));
f(-1/0, -1/0);
f(NaN, NaN);
}
with (o) {
f(undefined, void 0);
f(NaN, 0/0);
f(Infinity, 1/0);
f(-Infinity, -(1/0));
f(-Infinity, -1/0);
f(9 + undefined, 9 + void 0);
}
}
expect_stdout: true
}
assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
options = {
unused: true,
evaluate: true,
dead_code: true,
conditionals: true,
comparisons: true,
booleans: true,
hoist_funs: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
sequences: false,
keep_infinity: true,
}
input: {
var f = console.log;
var o = {
undefined : 3,
NaN : 4,
Infinity : 5,
};
if (o) {
f(undefined, void 0);
f(NaN, 0/0);
f(Infinity, 1/0);
f(-Infinity, -(1/0));
f(2 + 7 + undefined, 2 + 7 + void 0);
}
with (o) {
f(undefined, void 0);
f(NaN, 0/0);
f(Infinity, 1/0);
f(-Infinity, -(1/0));
f(2 + 7 + undefined, 2 + 7 + void 0);
}
}
expect: {
var f = console.log, o = {
undefined : 3,
NaN : 4,
Infinity : 5
};
if (o) {
f(void 0, void 0);
f(NaN, NaN);
f(Infinity, 1/0);
f(-Infinity, -1/0);
f(NaN, NaN);
}
with (o) {
f(undefined, void 0);
f(NaN, 0/0);
f(Infinity, 1/0);
f(-Infinity, -1/0);
f(9 + undefined, 9 + void 0);
}
}
expect_stdout: true
}

View File

@@ -49,4 +49,3 @@ mangle_keep_fnames_true: {
}
}
}

View File

@@ -0,0 +1,76 @@
issue_1212_debug_false: {
options = {
global_defs : { DEBUG: false },
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,
}
input: {
class foo {
bar() {
if (DEBUG)
console.log("DEV");
else
console.log("PROD");
}
}
new foo().bar();
}
expect: {
class foo{
bar() { console.log("PROD") }
}
(new foo).bar();
}
}
issue_1212_debug_true: {
options = {
global_defs : { DEBUG: 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,
}
input: {
class foo {
bar() {
if (DEBUG)
console.log("DEV");
else
console.log("PROD");
}
}
new foo().bar();
}
expect: {
class foo{
bar() { console.log("DEV") }
}
(new foo).bar();
}
}

View File

@@ -154,12 +154,12 @@ should_warn: {
"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: Boolean || always true [test/compress/issue-1261.js:130,8]",
"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: Boolean && always false [test/compress/issue-1261.js:132,8]",
"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]",

View File

@@ -46,4 +46,5 @@ string_plus_optimization: {
}
foo();
}
expect_stdout: true
}

View File

@@ -1,6 +1,6 @@
issue_1321_no_debug: {
mangle_props = {
ignore_quoted: true
keep_quoted: true
}
input: {
var x = {};
@@ -10,15 +10,16 @@ issue_1321_no_debug: {
}
expect: {
var x = {};
x.b = 1;
x["a"] = 2 * x.b;
console.log(x.b, x["a"]);
x.o = 1;
x["a"] = 2 * x.o;
console.log(x.o, x["a"]);
}
expect_stdout: true
}
issue_1321_debug: {
mangle_props = {
ignore_quoted: true,
keep_quoted: true,
debug: ""
}
input: {
@@ -29,15 +30,16 @@ issue_1321_debug: {
}
expect: {
var x = {};
x.a = 1;
x["_$foo$_"] = 2 * x.a;
console.log(x.a, x["_$foo$_"]);
x.o = 1;
x["_$foo$_"] = 2 * x.o;
console.log(x.o, x["_$foo$_"]);
}
expect_stdout: true
}
issue_1321_with_quoted: {
mangle_props = {
ignore_quoted: false
keep_quoted: false
}
input: {
var x = {};
@@ -47,8 +49,9 @@ issue_1321_with_quoted: {
}
expect: {
var x = {};
x.a = 1;
x["b"] = 2 * x.a;
console.log(x.a, x["b"]);
x.o = 1;
x["x"] = 2 * x.o;
console.log(x.o, x["x"]);
}
expect_stdout: true
}

View File

@@ -2,6 +2,7 @@
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true
}
@@ -19,12 +20,7 @@ unsafe_undefined: {
expect: {
function f(n) {
return function() {
if (a)
return b;
if (c)
return d;
else
return n;
return a ? b : c ? d : n;
};
}
}
@@ -32,6 +28,7 @@ unsafe_undefined: {
keep_fnames: {
options = {
conditionals: true,
if_return: true,
unsafe: true
}
@@ -57,12 +54,7 @@ keep_fnames: {
function n(n) {
return n * n;
}
if (a)
return b;
if (c)
return d;
else
return r;
return a ? b : c ? d : r;
};
}
}

View File

@@ -23,7 +23,7 @@ typeof_eq_undefined: {
typeof_eq_undefined_ie8: {
options = {
comparisons: true,
screw_ie8: false
ie8: true,
}
input: {
var a = typeof b != "undefined";

View File

@@ -42,4 +42,5 @@ conditional_false_stray_else_in_loop: {
}
}
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);"
expect_stdout: true
}

291
test/compress/issue-1466.js Normal file
View File

@@ -0,0 +1,291 @@
same_variable_in_multiple_for_loop: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let i = 0; i < 3; i++) {
let a = 100;
console.log(i, a);
for (let i = 0; i < 2; i++) {
console.log(i, a);
let c = 2;
console.log(c);
}
}
}
expect: {
for (let o = 0; o < 3; o++) {
let l = 100;
console.log(o, l);
for (let o = 0; o < 2; o++) {
console.log(o, l);
let e = 2;
console.log(e);
}
}
}
expect_stdout: true
}
same_variable_in_multiple_forOf: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp of test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let tmp of dd) {
console.log(tmp);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o of test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o of e)
console.log(o);
}
}
expect_stdout: true
}
same_variable_in_multiple_forIn: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp in test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let tmp in test) {
console.log(tmp);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let e in test) {
console.log(e);
let t;
t = [ "e", "f", "g" ];
for (let e in test)
console.log(e);
}
}
expect_stdout: true
}
different_variable_in_multiple_for_loop: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let i = 0; i < 3; i++) {
let a = 100;
console.log(i, a);
for (let j = 0; j < 2; j++) {
console.log(j, a);
let c = 2;
console.log(c);
}
}
}
expect: {
for (let o = 0; o < 3; o++) {
let l = 100;
console.log(o, l);
for (let o = 0; o < 2; o++) {
console.log(o, l);
let e = 2;
console.log(e);
}
}
}
expect_stdout: true
}
different_variable_in_multiple_forOf: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp of test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let t of dd) {
console.log(t);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let o of test) {
console.log(o);
let e;
e = [ "e", "f", "g" ];
for (let o of e)
console.log(o);
}
}
expect_stdout: true
}
different_variable_in_multiple_forIn: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
var test = [ "a", "b", "c" ];
for (let tmp in test) {
console.log(tmp);
let dd;
dd = [ "e", "f", "g" ];
for (let t in test) {
console.log(t);
}
}
}
expect: {
var test = [ "a", "b", "c" ];
for (let e in test) {
console.log(e);
let t;
t = [ "e", "f", "g" ];
for (let e in test)
console.log(e);
}
}
expect_stdout: true
}
more_variable_in_multiple_for: {
options = {
hoist_funs: true,
dead_code: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: false,
keep_fargs: true,
if_return: true,
join_vars: true,
cascade: true,
side_effects: true,
collapse_vars: true,
}
mangle = {}
input: {
for (let a = 9, i = 0; i < 20; i += a) {
let b = a++ + i;
console.log(a, b, i);
for (let k = b, m = b*b, i = 0; i < 10; i++) {
console.log(a, b, m, k, i);
}
}
}
expect: {
for (let o = 9, l = 0; l < 20; l += o) {
let e = o++ + l;
console.log(o, e, l);
for (let l = e, t = e * e, c = 0; c < 10; c++)
console.log(o, e, t, l, c);
}
}
expect_stdout: true
}

View File

@@ -0,0 +1,19 @@
inner_reference: {
options = {
side_effects: true,
}
input: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!function g(a) {
return a;
}(42);
}
expect: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!void 0;
}
}

View File

@@ -0,0 +1,99 @@
screw_ie8: {
options = {
ie8: false,
}
mangle = {
ie8: false,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(o){console.log(o)}'
expect_stdout: [
"foo"
]
}
support_ie8: {
options = {
ie8: true,
}
mangle = {
ie8: true,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(x){console.log(x)}'
expect_stdout: "foo"
}
safe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: false,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}(1)());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : void 0;
};
}(1)());
}
expect_stdout: true
}
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}()());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : n;
};
}()());
}
expect_stdout: true
}
runtime_error: {
input: {
const a = 1;
console.log(a++);
}
expect: {
const a = 1;
console.log(a++);
}
expect_stdout: true
}

View File

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

View File

@@ -0,0 +1,88 @@
issue_1639_1: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
join_vars: true,
loops: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
var L1 = 5;
while (--L1 > 0) {
if ((--b), false) {
if (b) {
var ignore = 0;
}
}
}
console.log(a, b);
}
expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, !1) var ignore = 0;
console.log(a, b);
}
expect_stdout: true
}
issue_1639_2: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
join_vars: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
function f19() {
if (++a, false)
if (a)
if (++a);
}
f19();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f19() {
++a, 1;
}
f19(),
console.log(a, b);
}
expect_stdout: true
}
issue_1639_3: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
a++ && false && a ? 0 : 0;
console.log(a, b);
}
expect: {
var a = 100, b = 10;
a++,
console.log(a, b);
}
expect_stdout: true
}

View File

@@ -0,0 +1,45 @@
f7: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
dead_code: true,
drop_debugger: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
loops: true,
negate_iife: true,
passes: 3,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
var a = 100, b = 10;
function f22464() {
var brake146670 = 5;
while (((b = a) ? !a : ~a ? null : b += a) && --brake146670 > 0) {
}
}
f22464();
console.log(a, b);
}
expect_exact: [
"var b = 10;",
"",
"!function() {",
" for (;b = 100, !1; ) ;",
"}(), console.log(100, b);",
]
expect_stdout: true
}

161
test/compress/issue-1673.js Normal file
View File

@@ -0,0 +1,161 @@
side_effects_catch: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
try {
throw 0;
} catch (e) {
console.log("PASS");
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
try {
throw 0;
} catch (e) {
console.log("PASS");
}
})();
}
f();
}
expect_stdout: "PASS"
}
side_effects_else: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
function g() {
if (x);
else console.log("PASS");
}
g();
}
f(0);
}
expect: {
function f(x) {
(function() {
if (x);
else console.log("PASS");
})();
}
f(0);
}
expect_stdout: "PASS"
}
side_effects_finally: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
try {
x();
} catch (e) {
} finally {
console.log("PASS");
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
try {
x();
} catch (e) {
} finally {
console.log("PASS");
}
})();
}
f();
}
expect_stdout: "PASS"
}
side_effects_label: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
function g() {
L: {
console.log("PASS");
break L;
}
}
g();
}
f(0);
}
expect: {
function f(x) {
(function() {
L: {
console.log("PASS");
break L;
}
})();
}
f(0);
}
expect_stdout: "PASS"
}
side_effects_switch: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
switch (0) {
default:
case console.log("PASS"):
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
switch (0) {
default:
case console.log("PASS"):
}
})();
}
f();
}
expect_stdout: "PASS"
}

347
test/compress/issue-1704.js Normal file
View File

@@ -0,0 +1,347 @@
mangle_catch: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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: {
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"
}

View File

@@ -0,0 +1,97 @@
function_iife_catch: {
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: {
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: {
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: {
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

@@ -0,0 +1,54 @@
case_1: {
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;
switch (true) {
case a, true:
b = 2;
}
console.log(a, b);
}
expect_stdout: "0 2"
}
case_2: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a = 0, b = 1;
switch (0) {
default:
b = 2;
case a:
a = 3;
case 0:
}
console.log(a, b);
}
expect: {
var a = 0, b = 1;
switch (0) {
case a:
a = 3;
}
console.log(a, b);
}
expect_stdout: "3 1"
}

105
test/compress/issue-1770.js Normal file
View File

@@ -0,0 +1,105 @@
mangle_props: {
mangle_props = {}
input: {
var obj = {
undefined: 1,
NaN: 2,
Infinity: 3,
"-Infinity": 4,
null: 5,
};
console.log(
obj[void 0],
obj[undefined],
obj["undefined"],
obj[0/0],
obj[NaN],
obj["NaN"],
obj[1/0],
obj[Infinity],
obj["Infinity"],
obj[-1/0],
obj[-Infinity],
obj["-Infinity"],
obj[null],
obj["null"]
);
}
expect: {
var obj = {
undefined: 1,
NaN: 2,
Infinity: 3,
"-Infinity": 4,
null: 5,
};
console.log(
obj[void 0],
obj[void 0],
obj["undefined"],
obj[0/0],
obj[NaN],
obj["NaN"],
obj[1/0],
obj[1/0],
obj["Infinity"],
obj[-1/0],
obj[-1/0],
obj["-Infinity"],
obj[null],
obj["null"]
);
}
expect_stdout: "1 1 1 2 2 2 3 3 3 4 4 4 5 5"
}
numeric_literal: {
beautify = {
beautify: true,
}
mangle_props = {}
input: {
var obj = {
0: 0,
"-0": 1,
42: 2,
"42": 3,
0x25: 4,
"0x25": 5,
1E42: 6,
"1E42": 7,
"1e+42": 8,
};
console.log(obj[-0], obj[-""], obj["-0"]);
console.log(obj[42], obj["42"]);
console.log(obj[0x25], obj["0x25"], obj[37], obj["37"]);
console.log(obj[1E42], obj["1E42"], obj["1e+42"]);
}
expect_exact: [
'var obj = {',
' 0: 0,',
' "-0": 1,',
' 42: 2,',
' "42": 3,',
' 37: 4,',
' o: 5,',
' 1e42: 6,',
' b: 7,',
' "1e+42": 8',
'};',
'',
'console.log(obj[-0], obj[-""], obj["-0"]);',
'',
'console.log(obj[42], obj["42"]);',
'',
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
'',
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
]
expect_stdout: [
"0 0 1",
"3 3",
"4 5 4 4",
"8 7 8",
]
}

View File

@@ -0,0 +1,16 @@
unary_prefix: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
var x = -(2 / 3);
return x;
}());
}
expect_exact: "console.log(-2/3);"
expect_stdout: true
}

134
test/compress/issue-1833.js Normal file
View File

@@ -0,0 +1,134 @@
iife_for: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: for (;;) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: for (;;) break L;
}();
}();
}
}
iife_for_in: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: for (var a in x) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: for (var a in x) break L;
}();
}();
}
}
iife_do: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: do {
break L;
} while (1);
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: do {
break L;
} while (1);
}();
}();
}
}
iife_while: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: while (1) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: while (1) break L;
}();
}();
}
}
label_do: {
options = {
evaluate: true,
loops: true,
}
input: {
L: do {
continue L;
} while (0);
}
expect: {
L: do {
continue L;
} while (0);
}
}
label_while: {
options = {
evaluate: true,
dead_code: true,
loops: true,
}
input: {
function f() {
L: while (0) continue L;
}
}
expect_exact: "function f(){L:;}"
}

View File

@@ -0,0 +1,31 @@
operator: {
input: {
a. //comment
typeof
}
expect_exact: "a.typeof;"
}
name: {
input: {
a. //comment
b
}
expect_exact: "a.b;"
}
keyword: {
input: {
a. //comment
default
}
expect_exact: "a.default;"
}
atom: {
input: {
a. //comment
true
}
expect_exact: "a.true;"
}

281
test/compress/issue-2001.js Normal file
View File

@@ -0,0 +1,281 @@
export_func_1: {
options = {
hoist_funs: true,
toplevel: true,
unused: true,
}
input: {
export function f(){};
}
expect_exact: "export function f(){};"
}
export_func_2: {
options = {
hoist_funs: true,
side_effects: false,
toplevel: true,
unused: true,
}
input: {
export function f(){}(1);
}
expect_exact: "export function f(){};1;"
}
export_func_3: {
options = {
hoist_funs: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
export function f(){}(1);
}
expect_exact: "export function f(){};"
}
export_default_func_1: {
options = {
hoist_funs: true,
toplevel: true,
unused: true,
}
input: {
export default function f(){};
}
expect_exact: "export default function f(){};"
}
export_default_func_2: {
options = {
hoist_funs: true,
side_effects: false,
toplevel: true,
unused: true,
}
input: {
export default function f(){}(1);
}
expect_exact: "export default function f(){};1;"
}
export_default_func_3: {
options = {
hoist_funs: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
export default function f(){}(1);
}
expect_exact: "export default function f(){};"
}
export_class_1: {
options = {
hoist_funs: true,
toplevel: true,
unused: true,
}
input: {
export class C {};
}
expect_exact: "export class C{};"
}
export_class_2: {
options = {
hoist_funs: true,
side_effects: false,
toplevel: true,
unused: true,
}
input: {
export class C {}(1);
}
expect_exact: "export class C{};1;"
}
export_class_3: {
options = {
hoist_funs: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
export class C {}(1);
}
expect_exact: "export class C{};"
}
export_default_class_1: {
options = {
hoist_funs: true,
toplevel: true,
unused: true,
}
input: {
export default class C {};
}
expect_exact: "export default class C{};"
}
export_default_class_2: {
options = {
hoist_funs: true,
side_effects: false,
toplevel: true,
unused: true,
}
input: {
export default class C {}(1);
}
expect_exact: "export default class C{};1;"
}
export_default_class_3: {
options = {
hoist_funs: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
export default class C {}(1);
}
expect_exact: "export default class C{};"
}
export_mangle_1: {
mangle = {
toplevel: true,
}
input: {
export function foo(one, two) {
return one - two;
};
}
expect_exact: "export function foo(o,n){return o-n};"
}
export_mangle_2: {
mangle = {
toplevel: true,
}
input: {
export default function foo(one, two) {
return one - two;
};
}
expect_exact: "export default function foo(o,t){return o-t};"
}
export_mangle_3: {
options = {
collapse_vars: true,
}
mangle = {
toplevel: true,
}
input: {
export class C {
go(one, two) {
var z = one;
return one - two + z;
}
};
}
expect_exact: "export class C{go(r,e){return r-e+r}};"
}
export_mangle_4: {
options = {
collapse_vars: true,
}
mangle = {
toplevel: true,
}
input: {
export default class C {
go(one, two) {
var z = one;
return one - two + z;
}
};
}
expect_exact: "export default class C{go(e,r){return e-r+e}};"
}
export_mangle_5: {
mangle = {
toplevel: true,
}
input: {
export default {
prop: function(one, two) {
return one - two;
}
};
}
expect_exact: "export default{prop:function(r,t){return r-t}};"
}
export_mangle_6: {
mangle = {
toplevel: true,
}
input: {
var baz = 2;
export let foo = 1, bar = baz;
}
expect_exact: "var o=2;export let foo=1,bar=o;"
}
export_toplevel_1: {
options = {
toplevel: true,
unused: true,
}
input: {
function f(){}
export function g(){};
export default function h(){};
}
expect: {
export function g(){};
export default function h(){};
}
}
export_toplevel_2: {
options = {
toplevel: true,
unused: true,
}
input: {
class A {}
export class B {};
export default class C {};
}
expect: {
export class B {};
export default class C {};
}
}
export_default_func_ref: {
options = {
hoist_funs: true,
toplevel: true,
unused: true,
}
input: {
export default function f(){};
f();
}
expect_exact: "export default function f(){};f();"
}

View File

@@ -0,0 +1,56 @@
compress_new_function: {
options = {
unsafe: true,
unsafe_Func: true,
}
input: {
new Function("aa, bb", 'return aa;');
}
expect: {
Function("n,r", "return n");
}
}
compress_new_function_with_destruct: {
options = {
unsafe: true,
unsafe_Func: true,
ecma: 6
}
beautify = {
ecma: 6
}
input: {
new Function("aa, [bb]", 'return aa;');
new Function("aa, {bb}", 'return aa;');
new Function("[[aa]], [{bb}]", 'return aa;');
}
expect: {
Function("n,[r]", "return n");
Function("n,{bb:b}", "return n");
Function("[[n]],[{bb:b}]", "return n");
}
}
compress_new_function_with_destruct_arrows: {
options = {
arrows: true,
unsafe: true,
unsafe_Func: true,
ecma: 6
}
beautify = {
ecma: 6
}
input: {
new Function("aa, [bb]", 'return aa;');
new Function("aa, {bb}", 'return aa;');
new Function("[[aa]], [{bb}]", 'return aa;');
}
expect: {
Function("n,[a]", "return n");
Function("b,{bb:n}", "return b");
Function("[[b]],[{bb:n}]", "return b");
}
}

483
test/compress/issue-281.js Normal file
View File

@@ -0,0 +1,483 @@
collapse_vars_constants: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f1(x) {
var a = 4, b = x.prop, c = 5, d = sideeffect1(), e = sideeffect2();
return b + (function() { return d - a * e - c; })();
}
function f2(x) {
var a = 4, b = x.prop, c = 5, not_used = sideeffect1(), e = sideeffect2();
return b + (function() { return -a * e - c; })();
}
}
expect: {
function f1(x) {
var b = x.prop, d = sideeffect1(), e = sideeffect2();
return b + (d - 4 * e - 5);
}
function f2(x) {
var b = x.prop;
sideeffect1();
return b + (-4 * sideeffect2() - 5);
}
}
}
modified: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
function f5(b) {
var a = function() {
return b;
}();
return b++ + a;
}
console.log(f5(1));
}
expect: {
function f5(b) {
var a = b;
return b++ + a;
}
console.log(f5(1));
}
expect_stdout: "2"
}
ref_scope: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
console.log(function() {
var a = 1, b = 2, c = 3;
var a = c++, b = b /= a;
return function() {
return a;
}() + b;
}());
}
expect: {
console.log(function() {
var a = 1, b = 2, c = 3;
b = b /= a = c++;
return a + b;
}());
}
expect_stdout: true
}
safe_undefined: {
options = {
conditionals: true,
if_return: true,
inline: true,
unsafe: false,
unused: true,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}(1)());
}
expect: {
var a, c;
console.log(a ? b : c ? d : void 0);
}
expect_stdout: true
}
negate_iife_3: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
t ? console.log(true) : console.log(false);
}
}
negate_iife_3_off: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: false,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
t ? console.log(true) : console.log(false);
}
}
negate_iife_4: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
sequences: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
t ? console.log(true) : console.log(false), void console.log("something");
}
}
negate_iife_5: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
sequences: true,
}
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
t ? foo(true) : bar(false), void console.log("something");
}
}
negate_iife_5_off: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: false,
sequences: true,
};
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
t ? foo(true) : bar(false), void console.log("something");
}
}
issue_1254_negate_iife_true: {
options = {
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: 'void console.log("test");'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
options = {
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()()()()();
}
expect_exact: '(void console.log("test"))()()();'
}
negate_iife_issue_1073: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
reduce_vars: true,
sequences: true,
unused: true,
};
input: {
new (function(a) {
return function Foo() {
this.x = a;
console.log(this);
};
}(7))();
}
expect: {
new function() {
this.x = 7,
console.log(this);
}();
}
expect_stdout: true
}
issue_1288_side_effects: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
reduce_vars: true,
side_effects: true,
unused: true,
};
input: {
if (w) ;
else {
(function f() {})();
}
if (!x) {
(function() {
x = {};
})();
}
if (y)
(function() {})();
else
(function(z) {
return z;
})(0);
}
expect: {
w;
x || (x = {});
y;
}
}
inner_var_for_in_1: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
}
input: {
function f() {
var a = 1, b = 2;
for (b in (function() {
return x(a, b, c);
})()) {
var c = 3, d = 4;
x(a, b, c, d);
}
x(a, b, c, d);
}
}
expect: {
function f() {
var a = 1, b = 2;
for (b in x(1, b, c)) {
var c = 3, d = 4;
x(1, b, c, d);
}
x(1, b, c, d);
}
}
}
issue_1595_3: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
return g(a + 1);
})(2);
}
expect: {
g(3);
}
}
issue_1758: {
options = {
inline: true,
sequences: true,
side_effects: true,
}
input: {
console.log(function(c) {
var undefined = 42;
return function() {
c--;
c--, c.toString();
return;
}();
}());
}
expect: {
console.log(function(c) {
var undefined = 42;
return c--, c--, void c.toString();
}());
}
expect_stdout: "undefined"
}
wrap_iife: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: 'void console.log("test");'
}
wrap_iife_in_expression: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
foo = (function () {
return bar();
})();
}
expect_exact: 'foo=bar();'
}
wrap_iife_in_return_call: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
(function() {
return (function() {
console.log('test')
})();
})()();
}
expect_exact: '(void console.log("test"))();'
}
pure_annotation: {
options = {
inline: true,
side_effects: true,
}
input: {
/*@__PURE__*/(function() {
console.log("hello");
}());
}
expect_exact: ""
}
drop_fargs: {
options = {
cascade: true,
inline: true,
keep_fargs: false,
side_effects: true,
unused: true,
}
input: {
var a = 1;
!function(a_1) {
a++;
}(a++ + (a && a.var));
console.log(a);
}
expect: {
var a = 1;
!function() {
a++;
}(++a && a.var);
console.log(a);
}
expect_stdout: "3"
}
keep_fargs: {
options = {
cascade: true,
inline: true,
keep_fargs: true,
side_effects: true,
unused: true,
}
input: {
var a = 1;
!function(a_1) {
a++;
}(a++ + (a && a.var));
console.log(a);
}
expect: {
var a = 1;
!function(a_1) {
a++;
}(++a && a.var);
console.log(a);
}
expect_stdout: "3"
}

View File

@@ -0,0 +1,55 @@
collapse: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f1() {
var a;
a = typeof b === 'function' ? b() : b;
return a !== undefined && c();
}
function f2(b) {
var a;
b = c();
a = typeof b === 'function' ? b() : b;
return 'stirng' == typeof a && d();
}
function f3(c) {
var a;
a = b(a / 2);
if (a < 0) {
a++;
++c;
return c / 2;
}
}
function f4(c) {
var a;
a = b(a / 2);
if (a < 0) {
a++;
c++;
return c / 2;
}
}
}
expect: {
function f1() {
return void 0 !== ('function' === typeof b ? b() : b) && c();
}
function f2(b) {
return b = c(), 'stirng' == typeof ('function' === typeof b ? b() : b) && d();
}
function f3(c) {
var a;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
function f4(c) {
var a;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
}
}

View File

@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
}
expect: {
(1/0).toString();
NaN.toString(); // transformation to 0/0 dropped
NaN.toString();
}
}
@@ -23,3 +23,135 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
NaN.toString();
}
}
NaN_and_Infinity_must_have_parens_evaluate: {
options = {
evaluate: true,
}
input: {
(123456789 / 0).toString();
(+"foo").toString();
}
expect: {
(1/0).toString();
NaN.toString();
}
}
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined_evaluate: {
options = {
evaluate: true,
}
input: {
var Infinity, NaN;
(123456789 / 0).toString();
(+"foo").toString();
}
expect: {
var Infinity, NaN;
(1/0).toString();
(0/0).toString();
}
}
beautify_off_1: {
options = {
evaluate: true,
}
beautify = {
beautify: false,
}
input: {
var NaN;
console.log(
null,
undefined,
Infinity,
NaN,
Infinity * undefined,
Infinity.toString(),
NaN.toString(),
(Infinity * undefined).toString()
);
}
expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());"
expect_stdout: true
}
beautify_off_2: {
options = {
evaluate: true,
}
beautify = {
beautify: false,
}
input: {
console.log(
null.toString(),
undefined.toString()
);
}
expect_exact: "console.log(null.toString(),(void 0).toString());"
}
beautify_on_1: {
options = {
evaluate: true,
}
beautify = {
beautify: true,
}
input: {
var NaN;
console.log(
null,
undefined,
Infinity,
NaN,
Infinity * undefined,
Infinity.toString(),
NaN.toString(),
(Infinity * undefined).toString()
);
}
expect_exact: [
"var NaN;",
"",
"console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());",
]
expect_stdout: true
}
beautify_on_2: {
options = {
evaluate: true,
}
beautify = {
beautify: true,
}
input: {
console.log(
null.toString(),
undefined.toString()
);
}
expect_exact: "console.log(null.toString(), (void 0).toString());"
}
issue_1724: {
input: {
var a = 0;
++a % Infinity | Infinity ? a++ : 0;
console.log(a);
}
expect_exact: "var a=0;++a%(1/0)|1/0?a++:0;console.log(a);"
expect_stdout: "2"
}
issue_1725: {
input: {
([].length === 0) % Infinity ? console.log("PASS") : console.log("FAIL");
}
expect_exact: '(0===[].length)%(1/0)?console.log("PASS"):console.log("FAIL");'
expect_stdout: "PASS"
}

320
test/compress/issue-640.js Normal file
View File

@@ -0,0 +1,320 @@
cond_5: {
options = {
conditionals: true,
expression: true,
}
input: {
if (some_condition()) {
if (some_other_condition()) {
do_something();
} else {
alternate();
}
} else {
alternate();
}
if (some_condition()) {
if (some_other_condition()) {
do_something();
}
}
}
expect: {
some_condition() && some_other_condition() ? do_something() : alternate();
if (some_condition() && some_other_condition()) do_something();
}
}
dead_code_const_annotation_regex: {
options = {
booleans : true,
conditionals : true,
dead_code : true,
evaluate : true,
expression : true,
loops : true,
}
input: {
var unused;
// @constraint this shouldn't be a constant
var CONST_FOO_ANN = false;
if (CONST_FOO_ANN) {
console.log("reachable");
}
}
expect: {
var unused;
var CONST_FOO_ANN = !1;
if (CONST_FOO_ANN) console.log('reachable');
}
expect_stdout: true
}
drop_console_2: {
options = {
drop_console: true,
expression: true,
}
input: {
console.log('foo');
console.log.apply(console, arguments);
}
expect: {
// with regular compression these will be stripped out as well
void 0;
void 0;
}
}
drop_value: {
options = {
expression: true,
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), {a:1, b:bar()};
}
}
wrongly_optimized: {
options = {
conditionals: true,
booleans: true,
evaluate: true,
expression: true,
}
input: {
function func() {
foo();
}
if (func() || true) {
bar();
}
}
expect: {
function func() {
foo();
}
// TODO: optimize to `func(), bar()`
if (func(), !0) bar();
}
}
negate_iife_1: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function(){ stuff() })();
}
expect: {
(function(){ stuff() })();
}
}
negate_iife_3: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
negate_iife_3_off: {
options = {
conditionals: true,
expression: true,
negate_iife: false,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
negate_iife_4: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
sequences: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
}
negate_iife_5: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
sequences: true,
}
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
}
negate_iife_5_off: {
options = {
conditionals: true,
expression: true,
negate_iife: false,
sequences: true,
};
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
}
issue_1254_negate_iife_true: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: '(function(){return function(){console.log("test")}})()();'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()()()()();
}
expect_exact: '(function(){return function(){console.log("test")}})()()()()();'
expect_stdout: true
}
conditional: {
options = {
expression: true,
pure_funcs: [ "pure" ],
side_effects: true,
}
input: {
pure(1 | a() ? 2 & b() : 7 ^ c());
pure(1 | a() ? 2 & b() : 5);
pure(1 | a() ? 4 : 7 ^ c());
pure(1 | a() ? 4 : 5);
pure(3 ? 2 & b() : 7 ^ c());
pure(3 ? 2 & b() : 5);
pure(3 ? 4 : 7 ^ c());
pure(3 ? 4 : 5);
}
expect: {
1 | a() ? b() : c();
1 | a() && b();
1 | a() || c();
a();
3 ? b() : c();
3 && b();
3 || c();
pure(3 ? 4 : 5);
}
}
limit_1: {
options = {
expression: true,
sequences: 3,
}
input: {
a;
b;
c;
d;
e;
f;
g;
h;
i;
j;
k;
}
expect: {
// Turned into a single return statement
// so it can no longer be split into lines
a,b,c,d,e,f,g,h,i,j,k;
}
}
iife: {
options = {
expression: true,
sequences: true,
}
input: {
x = 42;
(function a() {})();
!function b() {}();
~function c() {}();
+function d() {}();
-function e() {}();
void function f() {}();
typeof function g() {}();
}
expect: {
x = 42, function a() {}(), function b() {}(), function c() {}(),
function d() {}(), function e() {}(), function f() {}(), typeof function g() {}();
}
}

View File

@@ -1,37 +1,41 @@
dont_reuse_prop: {
mangle_props = {
regex: /asd/
};
}
input: {
"aaaaaaaaaabbbbb";
var obj = {};
obj.a = 123;
obj.asd = 256;
console.log(obj.a);
}
expect: {
"aaaaaaaaaabbbbb";
var obj = {};
obj.a = 123;
obj.b = 256;
console.log(obj.a);
}
expect_stdout: "123"
}
unmangleable_props_should_always_be_reserved: {
mangle_props = {
regex: /asd/
};
}
input: {
"aaaaaaaaaabbbbb";
var obj = {};
obj.asd = 256;
obj.a = 123;
console.log(obj.a);
}
expect: {
"aaaaaaaaaabbbbb";
var obj = {};
obj.b = 256;
obj.a = 123;
console.log(obj.a);
}
expect_stdout: "123"
}

View File

@@ -29,4 +29,5 @@ dont_mangle_arguments: {
})(5,6,7);
}
expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);"
expect_stdout: true
}

View File

@@ -0,0 +1,9 @@
template_strings: {
input: {
foo(
`<span>${contents}</span>`,
`<a href="${url}">${text}</a>`
);
}
expect_exact: "foo(`<span>${contents}</span>`,`<a href=\"${url}\">${text}</a>`);"
}

View File

@@ -50,6 +50,7 @@ this_binding_conditionals: {
this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
};
input: {
var c = a; c();

View File

@@ -42,6 +42,7 @@ eval_collapse_vars: {
eval("console.log(a);");
})(eval);
}
expect_stdout: true
}
eval_unused: {

View File

@@ -0,0 +1,40 @@
only_vars: {
options = { join_vars: true };
input: {
let netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
let netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}
issue_1079_with_vars: {
options = { join_vars: true };
input: {
var netmaskBinary = '';
for (var i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
for (var netmaskBinary = '', i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}
issue_1079_with_mixed: {
options = { join_vars: true };
input: {
var netmaskBinary = '';
for (let i = 0; i < netmaskBits; ++i) {
netmaskBinary += '1';
}
}
expect: {
var netmaskBinary = ''
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
}
}

View File

@@ -9,6 +9,7 @@ labels_1: {
expect: {
foo || console.log("bar");
}
expect_stdout: true
}
labels_2: {
@@ -40,6 +41,7 @@ labels_3: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
expect_stdout: true
}
labels_4: {
@@ -54,6 +56,7 @@ labels_4: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
expect_stdout: true
}
labels_5: {

View File

@@ -166,6 +166,7 @@ keep_collapse_const_in_own_block_scope: {
console.log(i);
console.log(c);
}
expect_stdout: true
}
keep_collapse_const_in_own_block_scope_2: {
@@ -186,6 +187,7 @@ keep_collapse_const_in_own_block_scope_2: {
console.log(i);
console.log(c);
}
expect_stdout: true
}
evaluate: {
@@ -216,3 +218,265 @@ evaluate: {
d();
}
}
issue_1532: {
options = {
evaluate: true,
loops: true,
}
input: {
function f(x, y) {
do {
if (x) break;
foo();
} while (false);
}
}
expect: {
function f(x, y) {
do {
if (x) break;
foo();
} while (false);
}
}
}
issue_186: {
beautify = {
beautify: false,
ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo())do{do{alert(x)}while(--x)}while(x);else bar();'
}
issue_186_ie8: {
beautify = {
beautify: false,
ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else bar();'
}
issue_186_beautify: {
beautify = {
beautify: true,
ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) do {',
' do {',
' alert(x);',
' } while (--x);',
'} while (x); else bar();',
]
}
issue_186_beautify_ie8: {
beautify = {
beautify: true,
ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else bar();',
]
}
issue_186_bracketize: {
beautify = {
beautify: false,
bracketize: true,
ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_bracketize_ie8: {
beautify = {
beautify: false,
bracketize: true,
ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_beautify_bracketize: {
beautify = {
beautify: true,
bracketize: true,
ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}
issue_186_beautify_bracketize_ie8: {
beautify = {
beautify: true,
bracketize: true,
ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}
issue_1648: {
options = {
join_vars: true,
loops: true,
passes: 2,
sequences: true,
unused: true,
}
input: {
function f() {
x();
var b = 1;
while (1);
}
}
expect_exact: "function f(){for(x();1;);}"
}
do_switch: {
options = {
evaluate: true,
loops: true,
}
input: {
do {
switch (a) {
case b:
continue;
}
} while (false);
}
expect: {
do {
switch (a) {
case b:
continue;
}
} while (false);
}
}

View File

@@ -7,7 +7,13 @@ too_short: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{\nc:42,\nd:a(),\ne:"foo"}}'
expect_exact: [
'function f(a){',
'return{',
'c:42,',
'd:a(),',
'e:"foo"}}',
]
expect_warnings: [
"WARN: Output exceeds 10 characters"
]
@@ -22,7 +28,12 @@ just_enough: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{c:42,\nd:a(),e:"foo"}\n}'
expect_exact: [
'function f(a){',
'return{c:42,',
'd:a(),e:"foo"}',
'}',
]
expect_warnings: [
]
}

View File

@@ -22,14 +22,25 @@ negate_iife_1_off: {
negate_iife_2: {
options = {
negate_iife: true
inline: true,
negate_iife: true,
};
input: {
(function(){ return {} })().x = 10; // should not transform this one
}
expect: {
(function(){ return {} })().x = 10;
}
expect_exact: "({}).x=10;"
}
negate_iife_2_side_effects: {
options = {
inline: true,
negate_iife: true,
side_effects: true,
}
input: {
(function(){ return {} })().x = 10;
}
expect_exact: "({}).x=10;"
}
negate_iife_3: {
@@ -37,11 +48,41 @@ negate_iife_3: {
negate_iife: true,
conditionals: true
};
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
negate_iife_3_evaluate: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
}
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true);
console.log(true);
}
expect_stdout: true
}
negate_iife_3_side_effects: {
options = {
conditionals: true,
negate_iife: true,
side_effects: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
@@ -50,12 +91,28 @@ negate_iife_3_off: {
negate_iife: false,
conditionals: true,
};
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
negate_iife_3_off_evaluate: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: false,
}
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true);
console.log(true);
}
expect_stdout: true
}
negate_iife_4: {
@@ -65,13 +122,13 @@ negate_iife_4: {
sequences: true
};
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true), function(){
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
@@ -86,7 +143,7 @@ sequence_off: {
};
input: {
function f() {
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
@@ -95,19 +152,19 @@ sequence_off: {
(function(){
console.log("something");
})();
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
expect: {
function f() {
!function(){ return true }() ? console.log(false) : console.log(true), function(){
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
function g() {
(function(){
console.log("something");
})(), function(){ return true }() ? console.log(true) : console.log(false);
})(), function(){ return t }() ? console.log(true) : console.log(false);
}
}
}
@@ -119,7 +176,7 @@ negate_iife_5: {
conditionals: true,
};
input: {
if ((function(){ return true })()) {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
@@ -129,7 +186,7 @@ negate_iife_5: {
})();
}
expect: {
!function(){ return true }() ? bar(false) : foo(true), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
@@ -142,7 +199,7 @@ negate_iife_5_off: {
conditionals: true,
};
input: {
if ((function(){ return true })()) {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
@@ -152,7 +209,7 @@ negate_iife_5_off: {
})();
}
expect: {
!function(){ return true }() ? bar(false) : foo(true), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
@@ -188,6 +245,7 @@ negate_iife_nested: {
}(7);
}).f();
}
expect_stdout: true
}
negate_iife_nested_off: {
@@ -220,6 +278,7 @@ negate_iife_nested_off: {
})(7);
}).f();
}
expect_stdout: true
}
negate_iife_issue_1073: {
@@ -244,6 +303,7 @@ negate_iife_issue_1073: {
};
}(7))();
}
expect_stdout: true
}
issue_1254_negate_iife_false: {
@@ -258,6 +318,7 @@ issue_1254_negate_iife_false: {
})()();
}
expect_exact: '(function(){return function(){console.log("test")}})()();'
expect_stdout: true
}
issue_1254_negate_iife_true: {
@@ -272,6 +333,7 @@ issue_1254_negate_iife_true: {
})()();
}
expect_exact: '!function(){return function(){console.log("test")}}()();'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
@@ -286,12 +348,14 @@ issue_1254_negate_iife_nested: {
})()()()()();
}
expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
expect_stdout: true
}
issue_1288: {
options = {
negate_iife: true,
conditionals: true,
negate_iife: true,
side_effects: false,
};
input: {
if (w) ;
@@ -311,12 +375,44 @@ issue_1288: {
})(0);
}
expect: {
w || function f() {}();
x || function() {
w || !function f() {}();
x || !function() {
x = {};
}();
y ? function() {}() : function(z) {
y ? !function() {}() : !function(z) {
return z;
}(0);
}
}
issue_1288_side_effects: {
options = {
conditionals: true,
negate_iife: true,
side_effects: true,
}
input: {
if (w) ;
else {
(function f() {})();
}
if (!x) {
(function() {
x = {};
})();
}
if (y)
(function() {})();
else
(function(z) {
return z;
})(0);
}
expect: {
w;
x || function() {
x = {};
}();
y;
}
}

View File

@@ -82,3 +82,19 @@ new_with_unary_prefix: {
}
expect_exact: 'var bar=(+new Date).toString(32);';
}
new_with_assignement_expression: {
options = {
evaluate: true
}
input: {
var a;
new x(a = 5 * 2, b = [1, 2, 3], c = {a: "a", b: "b", cd: "c" + "d"});
new y([a, b] = [3, 4]);
}
expect: {
var a;
new x(a = 10, b = [1, 2, 3], c = {a: "a", b: "b", cd: "cd"});
new y([a, b] = [3, 4]);
}
}

View File

@@ -0,0 +1,38 @@
eval_let_6: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: ""
node_version: ">=6"
}
eval_let_4: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: SyntaxError("Block-scoped declarations (let, const, function, class) not yet supported outside strict mode")
node_version: "4"
}
eval_let_0: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: SyntaxError("Unexpected identifier")
node_version: "<=0.12"
}

View File

@@ -17,3 +17,188 @@ hex_numbers_in_parentheses_for_prototype_functions: {
}
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);"
}
comparisons: {
options = {
comparisons: true,
}
input: {
console.log(
~x === 42,
x % n === 42
);
}
expect: {
console.log(
42 == ~x,
x % n == 42
);
}
}
evaluate_1: {
options = {
evaluate: true,
unsafe_math: false,
}
input: {
console.log(
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3)
);
}
expect: {
console.log(
x + 1 + 2,
1 * x * 2,
+x + 1 + 2,
1 + x + 2 + 3,
3 | x,
1 + x-- + 2 + 3,
x*y + 2 + 1 + 3,
1 + (2 + x + 3),
2 + ~x + 3 + 1,
-y + (2 + ~x + 3),
0 & x,
2 + (x |= 0) + 3 + 1
);
}
}
evaluate_2: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
console.log(
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3)
);
}
expect: {
console.log(
x + 1 + 2,
2 * x,
3 + +x,
1 + x + 2 + 3,
3 | x,
6 + x--,
6 + x*y,
1 + (2 + x + 3),
0 & x,
6 + (x |= 0)
);
}
}
evaluate_3: {
options = {
evaluate: true,
unsafe: true,
unsafe_math: true,
}
input: {
console.log(1 + Number(x) + 2);
}
expect: {
console.log(3 + +x);
}
}
evaluate_4: {
options = {
evaluate: true,
}
input: {
console.log(
1+ +a,
+a+1,
1+-a,
-a+1,
+a+ +b,
+a+-b,
-a+ +b,
-a+-b
);
}
expect: {
console.log(
+a+1,
+a+1,
1-a,
1-a,
+a+ +b,
+a-b,
-a+ +b,
-a-b
);
}
}
issue_1710: {
options = {
evaluate: true,
}
input: {
var x = {};
console.log((x += 1) + -x);
}
expect: {
var x = {};
console.log((x += 1) + -x);
}
expect_stdout: true
}
unary_binary_parenthesis: {
input: {
var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ];
v.forEach(function(x) {
v.forEach(function(y) {
console.log(
+(x*y),
+(x/y),
+(x%y),
-(x*y),
-(x/y),
-(x%y)
);
});
});
}
expect: {
var v = [ 0, 1, NaN, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
v.forEach(function(x) {
v.forEach(function(y) {
console.log(
+x*y,
+x/y,
+x%y,
-x*y,
-x/y,
-x%y
);
});
});
}
expect_stdout: true
}

512
test/compress/object.js Normal file
View File

@@ -0,0 +1,512 @@
getter_setter: {
input: {
var get = "bar";
var a = {
get,
set: "foo",
get bar() {
return this.get;
},
get 5() {
return "five";
},
get 0xf55() {
return "f five five";
},
get "five"() {
return 5;
},
set one(value) {
this._one = value;
},
set 9(value) {
this._nine = value;
},
set 0b1010(value) {
this._ten = value;
},
set "eleven"(value) {
this._eleven = value;
}
};
var b = {
get() { return "gift"; },
set: function(code) { return "Storing code " + code; }
};
var c = {
["get"]: "foo",
["set"]: "bar"
};
var d = {
get: "foo",
set: "bar"
};
}
expect: {
var get = "bar";
var a = {
get,
set: "foo",
get bar() {
return this.get;
},
get 5() {
return "five";
},
get 0xf55() {
return "f five five";
},
get "five"() {
return 5;
},
set one(value) {
this._one = value;
},
set 9(value) {
this._nine = value;
},
set 0b1010(value) {
this._ten = value;
},
set "eleven"(value) {
this._eleven = value;
}
};
var b = {
get() { return "gift"; },
set: function(code) { return "Storing code " + code; }
};
var c = {
["get"]: "foo",
["set"]: "bar"
};
var d = {
get: "foo",
set: "bar"
};
}
}
getter_setter_mangler: {
mangle = {}
beautify = {
ecma: 6
}
input: {
function f(get,set) {
return {
get,
set,
get g(){},
set s(n){},
c,
a:1,
m(){}
};
}
}
expect_exact: "function f(t,e){return{get:t,set:e,get g(){},set s(t){},c,a:1,m(){}}}"
}
use_shorthand_opportunity: {
beautify = {
ecma: 6
}
input: {
var foo = 123;
var obj = {foo: foo};
}
expect_exact: "var foo=123;var obj={foo};"
}
computed_property_names: {
input: {
obj({ ["x" + "x"]: 6 });
}
expect_exact: 'obj({["x"+"x"]:6});'
}
computed_property_names_evaluated_1: {
options = {
evaluate: true
}
input: {
obj({
[1 + 1]: 2,
["x" + "x"]: 6
});
}
expect_exact: 'obj({[2]:2,["xx"]:6});'
}
computed_property_names_evaluated_2: {
options = {
evaluate: true
}
input: {
var foo = something();
var obj = {
[foo]() {
return "blah";
}
}
}
expect_exact: 'var foo=something();var obj={[foo](){return"blah"}};'
}
shorthand_properties: {
mangle = true;
input: {
(function() {
var prop = 1;
const value = {prop};
return value;
})();
}
expect: {
(function() {
var n = 1;
const r = {prop:n};
return r;
})();
}
}
concise_methods: {
beautify = {
ecma: 6
}
input: {
x = {
foo(a, b) {
return x;
}
}
y = {
foo([{a}]) {
return a;
},
bar(){}
}
}
expect_exact: "x={foo(a,b){return x}};y={foo([{a}]){return a},bar(){}};"
}
concise_methods_with_computed_property: {
options = {
evaluate: true
}
input: {
var foo = {
[Symbol.iterator]() {
return { /* stuff */ }
},
[1 + 2]() {
return 3;
},
["1" + "4"]() {
return 14;
}
}
}
expect: {
var foo = {
[Symbol.iterator]() {
return { /* stuff */ }
},
[3]() {
return 3;
},
["14"]() {
return 14;
}
}
}
}
concise_methods_with_computed_property2: {
options = {
evaluate: true
}
input: {
var foo = {
[[1]](){
return "success";
}
};
doSomething(foo[[1]]());
}
expect_exact: 'var foo={[[1]](){return"success"}};doSomething(foo[[1]]());'
}
concise_methods_with_various_property_names: {
input: {
var get = "bar";
var a = {
bar() {
return this.get;
},
5() {
return "five";
},
0xf55() {
return "f five five";
},
"five"() {
return 5;
},
0b1010(value) {
this._ten = value;
}
};
}
expect: {
var get = "bar";
var a = {
bar() {
return this.get;
},
5() {
return "five";
},
0xf55() {
return "f five five";
},
"five"() {
return 5;
},
0b1010(value) {
this._ten = value;
}
};
}
}
concise_methods_and_mangle_props: {
mangle_props = {
regex: /_/
};
input: {
function x() {
obj = {
_foo() { return 1; }
}
}
}
expect: {
function x() {
obj = {
o() { return 1; }
}
}
}
}
concise_generators: {
beautify = {
ecma: 6
}
input: {
x = {
*foo(a, b) {
return x;
}
}
y = {
*foo([{a}]) {
yield a;
},
bar(){}
}
}
expect_exact: "x={*foo(a,b){return x}};y={*foo([{a}]){yield a},bar(){}};"
}
concise_methods_and_keyword_names: {
input: {
x = {
catch() {},
throw() {}
}
}
expect: {
x={catch(){},throw(){}};
}
}
getter_setter_with_computed_value: {
input: {
class C {
get ['a']() {
return 'A';
}
set ['a'](value) {
do_something(a);
}
}
var x = {
get [a.b]() {
return 42;
}
};
class MyArray extends Array {
get [Symbol.species]() {
return Array;
}
}
}
expect_exact: 'class C{get["a"](){return"A"}set["a"](value){do_something(a)}}var x={get[a.b](){return 42}};class MyArray extends Array{get[Symbol.species](){return Array}}'
}
property_with_operator_value: {
input: {
var foo = {
"*": 1,
get "*"() {
return 2;
},
*"*"() {
return 3;
},
"%": 1,
get "%"() {
return 2;
},
*"%"() {
return 3;
}
}
class bar {
get "*"() {
return 1
}
*"*"() {
return 2;
}
get "%"() {
return 1
}
*"%"() {
return 2;
}
}
}
expect_exact: 'var foo={"*":1,get"*"(){return 2},*"*"(){return 3},"%":1,get"%"(){return 2},*"%"(){return 3}};class bar{get"*"(){return 1}*"*"(){return 2}get"%"(){return 1}*"%"(){return 2}}'
}
property_with_unprintable: {
input: {
var foo = {
"\x00\x01": "foo",
get "\x00\x01"() {
return "bar";
},
set "\x00\x01"(foo) {
save(foo);
},
*"\x00\x01"() {
return "foobar";
}
}
class bar {
get "\x00\x01"() {
return "bar"
}
set "\x00\x01"(foo) {
save(foo);
}
*"\x00\x01"() {
return "foobar";
}
}
}
expect_exact: 'var foo={"\\0\x01":"foo",get"\\0\x01"(){return"bar"},set"\\0\x01"(foo){save(foo)},*"\\0\x01"(){return"foobar"}};class bar{get"\\0\x01"(){return"bar"}set"\\0\x01"(foo){save(foo)}*"\\0\x01"(){return"foobar"}}'
}
property_with_unprintable_ascii_only: {
beautify = {
ascii_only: true,
}
input: {
var foo = {
"\x00\x01": "foo",
get "\x00\x01"() {
return "bar";
},
set "\x00\x01"(foo) {
save(foo);
},
*"\x00\x01"() {
return "foobar";
}
}
class bar {
get "\x00\x01"() {
return "bar"
}
set "\x00\x01"(foo) {
save(foo);
}
*"\x00\x01"() {
return "foobar";
}
}
}
expect_exact: 'var foo={"\\0\\x01":"foo",get"\\0\\x01"(){return"bar"},set"\\0\\x01"(foo){save(foo)},*"\\0\\x01"(){return"foobar"}};class bar{get"\\0\\x01"(){return"bar"}set"\\0\\x01"(foo){save(foo)}*"\\0\\x01"(){return"foobar"}}'
}
property_with_unprintable_ascii_only_static: {
beautify = {
ascii_only: true
}
input: {
class foo {
static get "\x02\x03"() {
return "bar";
}
static set "\x04\x05"(foo) {
save(foo);
}
}
}
expect_exact: 'class foo{static get"\\x02\\x03"(){return"bar"}static set"\\x04\\x05"(foo){save(foo)}}'
}
methods_and_getters_with_keep_quoted_props_enabled: {
beautify = {
quote_style: 3,
keep_quoted_props: true,
}
input: {
var obj = {
a() {},
"b"() {},
get c() { return "c"},
get "d"() { return "d"},
set e(a) { doSomething(a); },
set f(a) { doSomething(b); }
}
}
expect_exact: 'var obj={a(){},"b"(){},get c(){return"c"},get"d"(){return"d"},set e(a){doSomething(a)},set f(a){doSomething(b)}};'
}
allow_assignments_to_property_values: {
input: {
var foo = {123: foo = 123} = {foo: "456"};
}
expect: {
var foo = {123: foo = 123} = {foo: "456"};
}
}
variable_as_computed_property: {
input: {
function getLine(header) {
return {
[header]: {}
};
}
}
expect_exact: "function getLine(header){return{[header]:{}}}"
}

186
test/compress/parameters.js Normal file
View File

@@ -0,0 +1,186 @@
arrow_functions: {
options = {
arrows: true,
}
input: {
(a) => b; // 1 args
(a, b) => c; // n args
() => b; // 0 args
(a) => (b) => c; // func returns func returns func
(a) => ((b) => c); // So these parens are dropped
() => (b,c) => d; // func returns func returns func
a=>{return b;}
a => 'lel'; // Dropping the parens
}
expect_exact: "a=>b;(a,b)=>c;()=>b;a=>b=>c;a=>b=>c;()=>(b,c)=>d;a=>b;a=>\"lel\";"
}
arrow_return: {
options = {
arrows: true,
}
input: {
() => {};
() => { return; };
a => { return 1; }
a => { return -b }
a => { return b; var b; }
(x, y) => { return x - y; }
}
expect_exact: "()=>{};()=>{};a=>1;a=>-b;a=>{return b;var b};(x,y)=>x-y;"
}
regression_arrow_functions_and_hoist: {
options = {
hoist_vars: true,
hoist_funs: true
}
input: {
(a) => b;
}
expect_exact: "a=>b;"
}
regression_assign_arrow_functions: {
input: {
oninstall = e => false;
oninstall = () => false;
}
expect: {
oninstall=e=>false;
oninstall=()=>false;
}
}
destructuring_arguments_1: {
input: {
(function ( a ) { });
(function ( [ a ] ) { });
(function ( [ a, b ] ) { });
(function ( [ [ a ] ] ) { });
(function ( [ [ a, b ] ] ) { });
(function ( [ a, [ b ] ] ) { });
(function ( [ [ b ], a ] ) { });
(function ( { a } ) { });
(function ( { a, b } ) { });
(function ( [ { a } ] ) { });
(function ( [ { a, b } ] ) { });
(function ( [ a, { b } ] ) { });
(function ( [ { b }, a ] ) { });
( [ a ] ) => { };
( [ a, b ] ) => { };
( { a } ) => { };
( { a, b, c, d, e } ) => { };
( [ a ] ) => b;
( [ a, b ] ) => c;
( { a } ) => b;
( { a, b } ) => c;
}
expect: {
(function(a){});
(function([a]){});
(function([a,b]){});
(function([[a]]){});
(function([[a,b]]){});
(function([a,[b]]){});
(function([[b],a]){});
(function({a}){});
(function({a,b}){});
(function([{a}]){});
(function([{a,b}]){});
(function([a,{b}]){});
(function([{b},a]){});
([a])=>{};
([a,b])=>{};
({a})=>{};
({a,b,c,d,e})=>{};
([a])=>b;
([a,b])=>c;
({a})=>b;
({a,b})=>c;
}
}
destructuring_arguments_2: {
input: {
(function([]) {});
(function({}) {});
(function([,,,,,]) {});
(function ([a, {b: c}]) {});
(function ([...args]) {});
(function ({x,}) {});
class a { *method({ [thrower()]: x } = {}) {}};
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
}
expect: {
(function([]) {});
(function({}) {});
(function([,,,,,]) {});
(function ([a, {b: c}]) {});
(function ([...args]) {});
(function ({x,}) {});
class a { *method({ [thrower()]: x } = {}) {}};
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
}
}
destructuring_arguments_3: {
beautify = {
ecma: 6
}
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() {}) } = {};
}
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(){})}={};"
}
default_arguments: {
beautify = {
ecma: 6
}
input: {
function x(a = 6) { }
function x(a = (6 + 5)) { }
function x({ foo } = {}, [ bar ] = [ 1 ]) { }
}
expect_exact: "function x(a=6){}function x(a=6+5){}function x({foo}={},[bar]=[1]){}"
}
default_values_in_destructurings: {
beautify = {
ecma: 6
}
input: {
function x({a=(4), b}) {}
function x([b, c=(12)]) {}
var { x = (6), y } = x;
var [ x, y = (6) ] = x;
}
expect_exact: "function x({a=4,b}){}function x([b,c=12]){}var{x=6,y}=x;var[x,y=6]=x;"
}
accept_duplicated_parameters_in_non_strict_without_spread_or_default_assignment: {
input: {
function a(b, b){}
function b({c: test, c: test}){}
}
expect: {
function a(b, b){}
function b({c: test, c: test}){}
}
}

View File

@@ -13,7 +13,7 @@ keep_properties: {
dot_properties: {
options = {
properties: true,
screw_ie8: false
ie8: true,
};
input: {
a["foo"] = "bar";
@@ -36,7 +36,7 @@ dot_properties: {
dot_properties_es5: {
options = {
properties: true,
screw_ie8: true
ie8: false,
};
input: {
a["foo"] = "bar";
@@ -125,7 +125,7 @@ evaluate_string_length: {
mangle_properties: {
mangle_props = {
ignore_quoted: false
keep_quoted: false
};
input: {
a["foo"] = "bar";
@@ -135,11 +135,11 @@ mangle_properties: {
a['run']({color: "blue", foo: "baz"});
}
expect: {
a["a"] = "bar";
a.b = "red";
x = {c: 10};
a.d(x.c, a.a);
a['d']({b: "blue", a: "baz"});
a["o"] = "bar";
a.a = "red";
x = {r: 10};
a.b(x.r, a.o);
a['b']({a: "blue", o: "baz"});
}
}
@@ -148,7 +148,8 @@ mangle_unquoted_properties: {
properties: false
}
mangle_props = {
ignore_quoted: true
builtins: true,
keep_quoted: true
}
beautify = {
beautify: false,
@@ -177,16 +178,16 @@ mangle_unquoted_properties: {
function f1() {
a["foo"] = "bar";
a.color = "red";
a.b = 2;
x = {"bar": 10, c: 7};
a.c = 9;
a.o = 2;
x = {"bar": 10, f: 7};
a.f = 9;
}
function f2() {
a.foo = "bar";
a['color'] = "red";
x = {bar: 10, c: 7};
a.c = 9;
a.b = 3;
x = {bar: 10, f: 7};
a.f = 9;
a.o = 3;
}
}
}
@@ -233,12 +234,13 @@ mangle_debug_suffix: {
}
}
mangle_debug_suffix_ignore_quoted: {
mangle_debug_suffix_keep_quoted: {
options = {
properties: false
}
mangle_props = {
ignore_quoted: true,
builtins: true,
keep_quoted: true,
debug: "XYZ",
reserved: []
}
@@ -555,3 +557,105 @@ native_prototype: {
"".indexOf.call(e, "bar");
}
}
accessor_boolean: {
input: {
var a = 1;
var b = {
get true() {
return a;
},
set false(c) {
a = c;
}
};
console.log(b.true, b.false = 2, b.true);
}
expect_exact: 'var a=1;var b={get true(){return a},set false(c){a=c}};console.log(b.true,b.false=2,b.true);'
expect_stdout: "1 2 2"
}
accessor_get_set: {
input: {
var a = 1;
var b = {
get set() {
return a;
},
set get(c) {
a = c;
}
};
console.log(b.set, b.get = 2, b.set);
}
expect_exact: 'var a=1;var b={get set(){return a},set get(c){a=c}};console.log(b.set,b.get=2,b.set);'
expect_stdout: "1 2 2"
}
accessor_null_undefined: {
input: {
var a = 1;
var b = {
get null() {
return a;
},
set undefined(c) {
a = c;
}
};
console.log(b.null, b.undefined = 2, b.null);
}
expect_exact: 'var a=1;var b={get null(){return a},set undefined(c){a=c}};console.log(b.null,b.undefined=2,b.null);'
expect_stdout: "1 2 2"
}
accessor_number: {
input: {
var a = 1;
var b = {
get 42() {
return a;
},
set 42(c) {
a = c;
}
};
console.log(b[42], b[42] = 2, b[42]);
}
expect_exact: 'var a=1;var b={get 42(){return a},set 42(c){a=c}};console.log(b[42],b[42]=2,b[42]);'
expect_stdout: "1 2 2"
}
accessor_string: {
input: {
var a = 1;
var b = {
get "a-b"() {
return a;
},
set "a-b"(c) {
a = c;
}
};
console.log(b["a-b"], b["a-b"] = 2, b["a-b"]);
}
expect_exact: 'var a=1;var b={get"a-b"(){return a},set"a-b"(c){a=c}};console.log(b["a-b"],b["a-b"]=2,b["a-b"]);'
expect_stdout: "1 2 2"
}
accessor_this: {
input: {
var a = 1;
var b = {
get this() {
return a;
},
set this(c) {
a = c;
}
};
console.log(b.this, b.this = 2, b.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"
}

View File

@@ -0,0 +1,387 @@
strict: {
options = {
pure_getters: "strict",
reduce_vars: false,
side_effects: true,
toplevel: true,
}
input: {
var a, b = null, c = {};
a.prop;
b.prop;
c.prop;
d.prop;
null.prop;
(void 0).prop;
undefined.prop;
}
expect: {
var a, b = null, c = {};
a.prop;
b.prop;
c.prop;
d.prop;
null.prop;
(void 0).prop;
(void 0).prop;
}
}
strict_reduce_vars: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a, b = null, c = {};
a.prop;
b.prop;
c.prop;
d.prop;
null.prop;
(void 0).prop;
undefined.prop;
}
expect: {
var a, b = null, c = {};
a.prop;
b.prop;
d.prop;
null.prop;
(void 0).prop;
(void 0).prop;
}
}
unsafe: {
options = {
pure_getters: true,
reduce_vars: false,
side_effects: true,
toplevel: true,
}
input: {
var a, b = null, c = {};
a.prop;
b.prop;
c.prop;
d.prop;
null.prop;
(void 0).prop;
undefined.prop;
}
expect: {
var a, b = null, c = {};
d;
null.prop;
(void 0).prop;
(void 0).prop;
}
}
unsafe_reduce_vars: {
options = {
pure_getters: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a, b = null, c = {};
a.prop;
b.prop;
c.prop;
d.prop;
null.prop;
(void 0).prop;
undefined.prop;
}
expect: {
var a, b = null, c = {};
d;
null.prop;
(void 0).prop;
(void 0).prop;
}
}
chained: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
a.b.c;
}
expect: {
a.b.c;
}
}
impure_getter_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect_stdout: "1"
}
impure_getter_2: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
// will produce incorrect output because getter is not pure
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {}
}
issue_2110_1: {
options = {
cascade: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function f() {}
function g() {
return this;
}
f.g = g;
return f.g();
}
console.log(typeof f());
}
expect: {
function f() {
function f() {}
return f.g = function() {
return this;
}, f.g();
}
console.log(typeof f());
}
expect_stdout: "function"
}
issue_2110_2: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
function f() {
function f() {}
function g() {
return this;
}
f.g = g;
return f.g();
}
console.log(typeof f());
}
expect: {
function f() {
function f() {}
f.g = function() {
return this;
};
return f.g();
}
console.log(typeof f());
}
expect_stdout: "function"
}
set_immutable_1: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
1..foo += "";
if (1..foo) console.log("FAIL");
else console.log("PASS");
}
expect_stdout: "PASS"
}
set_immutable_2: {
options = {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
var a = 1;
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: "PASS"
}
set_immutable_3: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: 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 += "";
if (1..foo) console.log("FAIL");
else console.log("PASS");
}
expect_stdout: true
}
set_immutable_4: {
options = {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
"use strict";
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
"use strict";
var a = 1;
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: true
}
set_mutable_1: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
!function a() {
a.foo += "";
if (a.foo) console.log("PASS");
else console.log("FAIL");
}();
}
expect: {
!function a() {
if (a.foo += "") console.log("PASS");
else console.log("FAIL");
}();
}
expect_stdout: "PASS"
}
set_mutable_2: {
options = {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
}
input: {
!function a() {
a.foo += "";
if (a.foo) console.log("PASS");
else console.log("FAIL");
}();
}
expect: {
!function a() {
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
}();
}
expect_stdout: "PASS"
}

File diff suppressed because it is too large Load Diff

14
test/compress/sandbox.js Normal file
View File

@@ -0,0 +1,14 @@
console_log: {
input: {
console.log("%% %s");
console.log("%% %s", "%s");
}
expect: {
console.log("%% %s");
console.log("%% %s", "%s");
}
expect_stdout: [
"%% %s",
"% %s",
]
}

View File

@@ -1,26 +1,61 @@
do_screw: {
options = { screw_ie8: true };
options = {
ie8: false,
}
beautify = {
screw_ie8: true,
ascii_only: true
};
input: f("\v");
expect_exact: 'f("\\v");';
ie8: false,
ascii_only: true,
}
input: {
f("\v");
}
expect_exact: 'f("\\v");'
}
dont_screw: {
options = { screw_ie8: false };
beautify = { screw_ie8: false, ascii_only: true };
options = {
ie8: true,
}
beautify = {
ie8: true,
ascii_only: true,
}
input: {
f("\v");
}
expect_exact: 'f("\\x0B");'
}
input: f("\v");
expect_exact: 'f("\\x0B");';
do_screw_constants: {
options = {
ie8: false,
}
input: {
f(undefined, Infinity);
}
expect_exact: "f(void 0,1/0);"
}
dont_screw_constants: {
options = {
ie8: true,
}
input: {
f(undefined, Infinity);
}
expect_exact: "f(undefined,Infinity);"
}
do_screw_try_catch: {
options = { screw_ie8: true };
mangle = { screw_ie8: true };
beautify = { screw_ie8: true };
options = {
ie8: false,
}
mangle = {
ie8: false,
}
beautify = {
ie8: false,
}
input: {
good = function(e){
return function(error){
@@ -46,11 +81,15 @@ do_screw_try_catch: {
}
dont_screw_try_catch: {
// This test is known to generate incorrect code for screw_ie8=false.
// Update expected result in the event this bug is ever fixed.
options = { screw_ie8: false };
mangle = { screw_ie8: false };
beautify = { screw_ie8: false };
options = {
ie8: true,
}
mangle = {
ie8: true,
}
beautify = {
ie8: true,
}
input: {
bad = function(e){
return function(error){
@@ -64,11 +103,11 @@ dont_screw_try_catch: {
}
expect: {
bad = function(n){
return function(n){
return function(t){
try{
t()
} catch(t) {
n(t)
n()
} catch(n) {
t(n)
}
}
};
@@ -76,9 +115,15 @@ dont_screw_try_catch: {
}
do_screw_try_catch_undefined: {
options = { screw_ie8: true };
mangle = { screw_ie8: true };
beautify = { screw_ie8: true };
options = {
ie8: false,
}
mangle = {
ie8: false,
}
beautify = {
ie8: false,
}
input: {
function a(b){
try {
@@ -101,14 +146,19 @@ do_screw_try_catch_undefined: {
return void 0===o
}
}
expect_stdout: true
}
dont_screw_try_catch_undefined: {
// This test is known to generate incorrect code for screw_ie8=false.
// Update expected result in the event this bug is ever fixed.
options = { screw_ie8: false };
mangle = { screw_ie8: false };
beautify = { screw_ie8: false };
options = {
ie8: true,
}
mangle = {
ie8: true,
}
beautify = {
ie8: true,
}
input: {
function a(b){
try {
@@ -121,14 +171,157 @@ dont_screw_try_catch_undefined: {
};
}
expect: {
function a(o){
function a(n){
try{
throw "Stuff"
} catch (n) {
console.log("caught: "+n)
} catch (undefined) {
console.log("caught: " + undefined)
}
console.log("undefined is " + n);
return o === n
console.log("undefined is " + undefined);
return n === undefined
}
}
expect_stdout: true
}
reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
ie8: true,
unused: true,
}
mangle = {
ie8: true,
}
input: {
function f() {
var a;
try {
x();
} catch (a) {
y();
}
alert(a);
}
}
expect: {
function f() {
var t;
try {
x();
} catch (t) {
y();
}
alert(t);
}
}
}
issue_1586_1: {
options = {
ie8: true,
}
mangle = {
ie8: true,
}
input: {
function f() {
try {
x();
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
}
issue_1586_2: {
options = {
ie8: false,
}
mangle = {
ie8: false,
}
input: {
function f() {
try {
x();
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
}
issue_2120_1: {
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: {
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"
}

View File

@@ -86,6 +86,7 @@ make_sequences_4: {
switch (x = 5, y) {}
with (x = 5, obj);
}
expect_stdout: true
}
lift_sequences_1: {
@@ -103,15 +104,18 @@ lift_sequences_1: {
lift_sequences_2: {
options = { sequences: true, evaluate: true };
input: {
var foo, bar;
var foo = 1, bar;
foo.x = (foo = {}, 10);
bar = (bar = {}, 10);
console.log(foo, bar);
}
expect: {
var foo, bar;
var foo = 1, bar;
foo.x = (foo = {}, 10),
bar = {}, bar = 10;
bar = {}, bar = 10,
console.log(foo, bar);
}
expect_stdout: true
}
lift_sequences_3: {
@@ -138,6 +142,23 @@ lift_sequences_4: {
}
}
lift_sequences_5: {
options = {
sequences: true,
}
input: {
var a = 2, b;
a *= (b, a = 4, 3);
console.log(a);
}
expect: {
var a = 2, b;
b, a *= (a = 4, 3),
console.log(a);
}
expect_stdout: "6"
}
for_sequences: {
options = { sequences: true };
input: {
@@ -230,6 +251,7 @@ negate_iife_for: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 5; i++) console.log(i);
}
expect_stdout: true
}
iife: {
@@ -248,6 +270,487 @@ iife: {
}
expect: {
x = 42, function a() {}(), function b() {}(), function c() {}(),
function d() {}(), function e() {}(), function f() {}(), function g() {}()
function d() {}(), function e() {}(), function f() {}(), function g() {}();
}
}
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
unsafe: true,
}
input: {
function f(undefined) {
if (a)
return b;
if (c)
return d;
}
function g(undefined) {
if (a)
return b;
if (c)
return d;
e();
}
}
expect: {
function f(undefined) {
return a ? b : c ? d : undefined;
}
function g(undefined) {
return a ? b : c ? d : void e();
}
}
}
issue_1685: {
options = {
cascade: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
function f() {
var a = (a--, delete a && --b);
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
var a = (a--, delete a && --b);
}
f();
console.log(a, b);
}
expect_stdout: true
}
func_def_1: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
return f = 0, !!f;
}
console.log(f());
}
expect: {
function f() {
return !!(f = 0);
}
console.log(f());
}
expect_stdout: "false"
}
func_def_2: {
options = {
cascade: true,
side_effects: true,
}
input: {
console.log(function f() {
return f = 0, !!f;
}());
}
expect: {
console.log(function f() {
return f = 0, !!f;
}());
}
expect_stdout: "true"
}
func_def_3: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
function g() {}
return g = 0, !!g;
}
console.log(f());
}
expect: {
function f() {
function g() {}
return !!(g = 0);
}
console.log(f());
}
expect_stdout: "false"
}
func_def_4: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
function g() {
return g = 0, !!g;
}
return g();
}
console.log(f());
}
expect: {
function f() {
function g() {
return !!(g = 0);
}
return g();
}
console.log(f());
}
expect_stdout: "false"
}
func_def_5: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
return function g(){
return g = 0, !!g;
}();
}
console.log(f());
}
expect: {
function f() {
return function g(){
return g = 0, !!g;
}();
}
console.log(f());
}
expect_stdout: "true"
}
issue_1758: {
options = {
sequences: true,
side_effects: true,
}
input: {
console.log(function(c) {
var undefined = 42;
return function() {
c--;
c--, c.toString();
return;
}();
}());
}
expect: {
console.log(function(c) {
var undefined = 42;
return function() {
return c--, c--, void c.toString();
}();
}());
}
expect_stdout: "undefined"
}
delete_seq_1: {
options = {
booleans: true,
side_effects: true,
}
input: {
console.log(delete (1, undefined));
console.log(delete (1, void 0));
console.log(delete (1, Infinity));
console.log(delete (1, 1 / 0));
console.log(delete (1, NaN));
console.log(delete (1, 0 / 0));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
delete_seq_2: {
options = {
booleans: true,
side_effects: true,
}
input: {
console.log(delete (1, 2, undefined));
console.log(delete (1, 2, void 0));
console.log(delete (1, 2, Infinity));
console.log(delete (1, 2, 1 / 0));
console.log(delete (1, 2, NaN));
console.log(delete (1, 2, 0 / 0));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
delete_seq_3: {
options = {
booleans: true,
keep_infinity: true,
side_effects: true,
}
input: {
console.log(delete (1, 2, undefined));
console.log(delete (1, 2, void 0));
console.log(delete (1, 2, Infinity));
console.log(delete (1, 2, 1 / 0));
console.log(delete (1, 2, NaN));
console.log(delete (1, 2, 0 / 0));
}
expect: {
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
console.log(!0);
}
expect_stdout: true
}
delete_seq_4: {
options = {
booleans: true,
sequences: true,
side_effects: true,
}
input: {
function f() {}
console.log(delete (f(), undefined));
console.log(delete (f(), void 0));
console.log(delete (f(), Infinity));
console.log(delete (f(), 1 / 0));
console.log(delete (f(), NaN));
console.log(delete (f(), 0 / 0));
}
expect: {
function f() {}
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0));
}
expect_stdout: true
}
delete_seq_5: {
options = {
booleans: true,
keep_infinity: true,
sequences: true,
side_effects: true,
}
input: {
function f() {}
console.log(delete (f(), undefined));
console.log(delete (f(), void 0));
console.log(delete (f(), Infinity));
console.log(delete (f(), 1 / 0));
console.log(delete (f(), NaN));
console.log(delete (f(), 0 / 0));
}
expect: {
function f() {}
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0)),
console.log((f(), !0));
}
expect_stdout: true
}
delete_seq_6: {
options = {
booleans: true,
side_effects: true,
}
input: {
var a;
console.log(delete (1, a));
}
expect: {
var a;
console.log(!0);
}
expect_stdout: true
}
side_effects: {
options = {
sequences: true,
side_effects: true,
}
input: {
0, a(), 1, b(), 2, c(), 3;
}
expect: {
a(), b(), c();
}
}
side_effects_cascade_1: {
options = {
cascade: true,
conditionals: true,
sequences: true,
side_effects: true,
}
input: {
function f(a, b) {
a -= 42;
if (a < 0) a = 0;
b.a = a;
}
}
expect: {
function f(a, b) {
(a -= 42) < 0 && (a = 0), b.a = a;
}
}
}
side_effects_cascade_2: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f(a, b) {
b = a,
!a + (b += a) || (b += a),
b = a,
b;
}
}
expect: {
function f(a, b) {
b = a,
!a + (b += a) || (b += a),
b = a;
}
}
}
side_effects_cascade_3: {
options = {
cascade: true,
conditionals: true,
side_effects: true,
}
input: {
function f(a, b) {
"foo" ^ (b += a),
b ? false : (b = a) ? -1 : (b -= a) - (b ^= a),
a-- || !a,
a;
}
}
expect: {
function f(a, b) {
!(b += a) && ((b = a) || (b -= a, b ^= a)),
--a;
}
}
}
issue_27: {
options = {
cascade: true,
passes: 2,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(jQuery) {
var $;
$ = jQuery;
$("body").addClass("foo");
})(jQuery);
}
expect: {
(function(jQuery) {
jQuery("body").addClass("foo");
})(jQuery);
}
}
reassign_const: {
options = {
cascade: true,
sequences: true,
side_effects: true,
}
input: {
function f() {
const a = 1;
a++;
return a;
}
console.log(f());
}
expect: {
function f() {
const a = 1;
return a++, a;
}
console.log(f());
}
expect_stdout: true
}
issue_2062: {
options = {
booleans: true,
cascade: true,
conditionals: true,
side_effects: true,
}
input: {
var a = 1;
if ([ a || a++ + a--, a++ + a--, a && a.var ]);
console.log(a);
}
expect: {
var a = 1;
a || (a++, a--), a++, --a && a.var;
console.log(a);
}
expect_stdout: "1"
}

View File

@@ -8,3 +8,12 @@ octal_escape_sequence: {
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
}
}
issue_1929: {
input: {
function f(s) {
return s.split(/[\\/]/);
}
}
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
}

9
test/compress/super.js Normal file
View File

@@ -0,0 +1,9 @@
super_can_be_parsed: {
input: {
super(1,2);
super.meth();
}
expect_exact: "super(1,2);super.meth();"
}

View File

@@ -1,5 +1,10 @@
constant_switch_1: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (1+1) {
case 1: foo(); break;
@@ -13,7 +18,12 @@ constant_switch_1: {
}
constant_switch_2: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (1) {
case 1: foo();
@@ -28,7 +38,12 @@ constant_switch_2: {
}
constant_switch_3: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (10) {
case 1: foo();
@@ -44,7 +59,12 @@ constant_switch_3: {
}
constant_switch_4: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (2) {
case 1:
@@ -65,7 +85,12 @@ constant_switch_4: {
}
constant_switch_5: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (1) {
case 1:
@@ -94,7 +119,12 @@ constant_switch_5: {
}
constant_switch_6: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
OUT: {
foo();
@@ -123,7 +153,12 @@ constant_switch_6: {
}
constant_switch_7: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
OUT: {
foo();
@@ -161,7 +196,12 @@ constant_switch_7: {
}
constant_switch_8: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
OUT: switch (1) {
case 1:
@@ -185,7 +225,12 @@ constant_switch_8: {
}
constant_switch_9: {
options = { dead_code: true, evaluate: true };
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
OUT: switch (1) {
case 1:
@@ -210,7 +255,10 @@ constant_switch_9: {
}
drop_default_1: {
options = { dead_code: true };
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case 'bar': baz();
@@ -225,7 +273,10 @@ drop_default_1: {
}
drop_default_2: {
options = { dead_code: true };
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case 'bar': baz(); break;
@@ -241,7 +292,10 @@ drop_default_2: {
}
keep_default: {
options = { dead_code: true };
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case 'bar': baz();
@@ -258,3 +312,507 @@ keep_default: {
}
}
}
issue_1663: {
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
var a = 100, b = 10;
function f() {
switch (1) {
case 1:
b = a++;
return ++b;
default:
var b;
}
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
var b;
b = a++;
return ++b;
}
f();
console.log(a, b);
}
expect_stdout: true
}
drop_case: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case 'bar': baz(); break;
case 'moo':
break;
}
}
expect: {
switch (foo) {
case 'bar': baz();
}
}
}
keep_case: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case 'bar': baz(); break;
case moo:
break;
}
}
expect: {
switch (foo) {
case 'bar': baz(); break;
case moo:
}
}
}
issue_376: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (true) {
case boolCondition:
console.log(1);
break;
case false:
console.log(2);
break;
}
}
expect: {
switch (true) {
case boolCondition:
console.log(1);
}
}
}
issue_441_1: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case bar:
qux();
break;
case baz:
qux();
break;
default:
qux();
break;
}
}
expect: {
switch (foo) {
case bar:
case baz:
default:
qux();
}
}
}
issue_441_2: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
case bar:
// TODO: Fold into the case below
qux();
break;
case fall:
case baz:
qux();
break;
default:
qux();
break;
}
}
expect: {
switch (foo) {
case bar:
qux();
break;
case fall:
case baz:
default:
qux();
}
}
}
issue_1674: {
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (0) {
default:
console.log("FAIL");
break;
case 0:
console.log("PASS");
break;
}
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_1679: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a = 100, b = 10;
function f() {
switch (--b) {
default:
case !function x() {}:
break;
case b--:
switch (0) {
default:
case a--:
}
break;
case (a++):
break;
}
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
switch (--b) {
default:
case !function x() {}:
break;
case b--:
switch (0) {
default:
case a--:
}
break;
case (a++):
}
}
f();
console.log(a, b);
}
expect_stdout: true
}
issue_1680_1: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
function f(x) {
console.log(x);
return x + 1;
}
switch (2) {
case f(0):
case f(1):
f(2);
case 2:
case f(3):
case f(4):
f(5);
}
}
expect: {
function f(x) {
console.log(x);
return x + 1;
}
switch (2) {
case f(0):
case f(1):
f(2);
case 2:
f(5);
}
}
expect_stdout: [
"0",
"1",
"2",
"5",
]
}
issue_1680_2: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = 100, b = 10;
switch (b) {
case a--:
break;
case b:
var c;
break;
case a:
break;
case a--:
break;
}
console.log(a, b);
}
expect: {
var a = 100, b = 10;
switch (b) {
case a--:
break;
case b:
var c;
break;
case a:
case a--:
}
console.log(a, b);
}
expect_stdout: true
}
issue_1690_1: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (console.log("PASS")) {}
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_1690_2: {
options = {
dead_code: false,
switches: true,
}
input: {
switch (console.log("PASS")) {}
}
expect: {
switch (console.log("PASS")) {}
}
expect_stdout: "PASS"
}
if_switch_typeof: {
options = {
conditionals: true,
dead_code: true,
side_effects: true,
switches: true,
}
input: {
if (a) switch(typeof b) {}
}
expect: {
a;
}
}
issue_1698: {
options = {
side_effects: true,
switches: true,
}
input: {
var a = 1;
!function() {
switch (a++) {}
}();
console.log(a);
}
expect: {
var a = 1;
!function() {
switch (a++) {}
}();
console.log(a);
}
expect_stdout: "2"
}
issue_1705_1: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
break;
}
}
expect: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
}
}
expect_stdout: true
}
issue_1705_2: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
switches: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
break;
}
}
expect: {
}
expect_stdout: true
}
issue_1705_3: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (a) {
case 0:
break;
default:
break;
}
}
expect: {
a;
}
expect_stdout: true
}
beautify: {
beautify = {
beautify: true,
}
input: {
switch (a) {
case 0:
case 1:
break;
case 2:
default:
}
switch (b) {
case 3:
foo();
bar();
default:
break;
}
}
expect_exact: [
"switch (a) {",
" case 0:",
" case 1:",
" break;",
"",
" case 2:",
" default:",
"}",
"",
"switch (b) {",
" case 3:",
" foo();",
" bar();",
"",
" default:",
" break;",
"}",
]
}
issue_1758: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = 1, b = 2;
switch (a--) {
default:
b++;
}
console.log(a, b);
}
expect: {
var a = 1, b = 2;
a--;
b++;
console.log(a, b);
}
expect_stdout: "0 3"
}

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