Compare commits

...

223 Commits

Author SHA1 Message Date
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
130 changed files with 15670 additions and 10423 deletions

View File

@@ -1,9 +1,20 @@
- Bug report or feature request? <!-- Note: sub-optimal but correct code is not a bug -->
- `uglify-js` version (`uglifyjs -V`)
- JavaScript input - ideally as small as possible.
- The `uglifyjs` CLI command executed or `minify()` options used.
- An example of JavaScript output produced and/or the error or warning.
**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: the release version of uglify-js only supports ES5. Those wishing
to minify ES6 should use the experimental harmony branch.
Note: `uglify-js` only supports ES5.
Those wishing to minify ES6 should use `uglify-es`.
-->

View File

@@ -1,5 +1,4 @@
language: node_js
before_install: "npm install -g npm"
node_js:
- "0.10"
- "0.12"

1299
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,633 +3,403 @@
"use strict";
var UglifyJS = require("../tools/node");
var sys = require("util");
var yargs = require("yargs");
var fs = require("fs");
var path = require("path");
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.")
.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:");
var defs = options[option];
var padding = "";
Object.keys(defs).map(function(name) {
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
return [ name, JSON.stringify(defs[name]) ];
}).forEach(function(tokens) {
text.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
});
text.push("");
}
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("--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 (ARGS.support_ie8 === true && ARGS.screw_ie8 !== true) {
screw_ie8 = false;
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
fatal("ERROR: cannot write source map to STDOUT");
}
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;
[
"compress",
"ie8",
"mangle",
"sourceMap",
"toplevel",
"wrap"
].forEach(function(name) {
if (name in program) {
options[name] = program[name];
}
});
if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) {
options.output.beautify = true;
}
}
if (ARGS.wrap_iife) {
if (COMPRESS) COMPRESS.negate_iife = false;
OUTPUT_OPTIONS.wrap_iife = true;
if (program.comments) {
if (typeof options.output != "object") options.output = {};
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
}
if (BEAUTIFY)
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
if (ARGS.comments === "") {
OUTPUT_OPTIONS.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 {
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);
});
}
if (typeof options.mangle != "object") options.mangle = {};
options.mangle.properties = program.mangleProps;
}
var cache;
if (program.nameCache) {
cache = JSON.parse(read_file(program.nameCache, "{}"));
if (options.mangle) {
if (typeof options.mangle != "object") options.mangle = {};
options.mangle.cache = to_cache("vars");
if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
options.mangle.properties.cache = to_cache("props");
}
}
}
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) {
console.error("WARN: Ignoring input files since --self was passed");
}
if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else if (program.args.length) {
simple_glob(program.args).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else {
OUTPUT_OPTIONS.comments = ARGS.comments;
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();
}
var files = ARGS._.slice();
if (process.platform === "win32")
files = UglifyJS.simple_glob(files);
if (ARGS.self) {
if (files.length > 0) {
print_error("WARN: Ignoring input files since --self was passed");
}
files = UglifyJS.FILES;
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
function convert_ast(fn) {
return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
}
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 = {};
var index = 0;
!function cb() {
if (index == files.length) return done();
var file = files[index++];
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, '/');
} 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
function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
console.error("WARN:", msg);
};
if (program.timings) options.timings = true;
try {
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;
});
}
else {
try {
TOPLEVEL = UglifyJS.parse(code, {
filename : file,
toplevel : TOPLEVEL,
expression : ARGS.expr,
bare_returns : ARGS.bare_returns,
});
} 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) {
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;
}
} catch (ex) {
fatal(ex);
}
var result = UglifyJS.minify(files, options);
if (result.error) {
var ex = result.error;
if (ex.name == "SyntaxError") {
console.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;
}
};
});
cb();
});
}();
console.error(line.slice(0, 80));
console.error(line.slice(0, col).replace(/\S/g, " ") + "^");
}
}
if (ex.defs) {
console.error("Supported options:");
console.error(ex.defs);
}
fatal(ex);
} else if (program.output == "ast") {
console.log(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];
});
return result;
}
return value;
}, 2));
} else if (program.output == "spidermonkey") {
console.log(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 {
console.log(result.code);
}
if (program.nameCache) {
fs.writeFileSync(program.nameCache, JSON.stringify(cache, function(key, value) {
return value instanceof UglifyJS.Dictionary ? value.toObject() : value;
}));
}
if (result.timings) for (var phase in result.timings) {
console.error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
}
}
function done() {
var OUTPUT_FILE = ARGS.o;
function fatal(message) {
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:")
console.error(message);
process.exit(1);
}
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;
// 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 (glob.match(/\*|\?/)) {
var dir = path.dirname(glob);
try {
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 {
var output = UglifyJS.OutputStream(OUTPUT_OPTIONS);
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) {
print_error(ex.message);
print_error("Supported options:");
print_error(sys.inspect(ex.defs));
process.exit(1);
}
return fs.readFileSync(path, "utf8");
} catch (ex) {
if (ex.code == "ENOENT" && default_value != null) return default_value;
fatal(ex);
}
}
if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
});
if (ARGS.wrap != null) {
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
}
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;
function parse_js(flag, constants) {
return function(value, options) {
options = options || {};
try {
regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null;
} catch (e) {
print_error("ERROR: Invalid --mangle-regex: " + e.message);
process.exit(1);
}
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();
var value = node.right;
if (!constants) {
options[name] = value;
} else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string);
} else {
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;
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();
}
});
}
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)
function to_string(value) {
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({
quote_keys: true
});
}
}));
}
}
}
/* -----[ 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;
try {
ast = UglifyJS.parse(x, { cli: true, expression: true });
} catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Error parsing arguments for flag `" + flag + "': " + x);
process.exit(1);
}
options[value] = null;
}
ast.walk(new UglifyJS.TreeWalker(function(node){
if (node instanceof UglifyJS.AST_Seq) return; // descend
if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string().replace(/-/g, "_");
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 options;
}
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();
function parse_source_map() {
var parse = parse_js("sourceMap", true);
return function(value, options) {
var hasContent = options && options.sourceMap && "content" in options.sourceMap;
var settings = parse(value, options);
if (!hasContent && settings.content && settings.content != "inline") {
console.error("INFO: Using input source map:", settings.content);
settings.content = read_file(settings.content, settings.content);
}
return settings;
}
}
function to_cache(key) {
if (cache[key]) {
cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props);
} else {
fs.readFile(filename, "utf-8", cb);
cache[key] = {
cname: -1,
props: new UglifyJS.Dictionary()
};
}
return cache[key];
}
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;
}
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;
}
return ret;
}
function print_error(msg) {
console.error("%s", msg);
}
function print(txt) {
console.log("%s", txt);
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
}

View File

@@ -182,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);
@@ -214,12 +206,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
clone: function(deep) {
var node = this._clone(deep);
if (deep) {
var refs = node.label.references;
var label = this.label;
var label = node.label;
var def = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === label) {
refs.push(node);
&& node.label && node.label.thedef === def) {
node.label.thedef = label;
label.references.push(node);
}
}));
}
@@ -336,62 +329,13 @@ 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 MAP.splice(body);
}
}));
return wrapped_tl;
@@ -411,75 +355,6 @@ var AST_Expansion = DEFNODE("Expansion", "expression", {
}
});
var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
$documentation: "A set of arrow function parameters or a sequence expression. This is used because when the parser sees a \"(\" it could be the start of a seq, or the start of a parameter list of an arrow function.",
$propdoc: {
expressions: "[AST_Expression|AST_Destructuring|AST_Expansion*] array of expressions or argument names or destructurings."
},
as_params: function (croak) {
// We don't want anything which doesn't belong in a destructuring
var root = this;
return this.expressions.map(function to_fun_args(ex, _, __, default_seen_above) {
var insert_default = function(ex, default_value) {
if (default_value) {
return new AST_DefaultAssign({
start: ex.start,
left: ex,
operator: "=",
right: default_value,
end: default_value.end
});
}
return ex;
}
if (ex instanceof AST_Object) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: false,
names: ex.properties.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_ObjectKeyVal) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key]);
}
ex.value = to_fun_args(ex.value, 0, [ex.key]);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Hole) {
return ex;
} else if (ex instanceof AST_Destructuring) {
if (ex.names.length == 0)
croak("Invalid destructuring function parameter", ex.start.line, ex.start.col);
ex.names = ex.names.map(to_fun_args);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_SymbolRef) {
return insert_default(new AST_SymbolFunarg({
name: ex.name,
start: ex.start,
end: ex.end
}), default_seen_above);
} else if (ex instanceof AST_Expansion) {
ex.expression = to_fun_args(ex.expression);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Array) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: true,
names: ex.elements.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_Assign) {
return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above);
} else {
croak("Invalid function parameter", ex.start.line, ex.start.col);
}
});
},
as_expr: function (croak) {
return AST_Seq.from_array(this.expressions);
}
});
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator", {
$documentation: "Base class for functions",
$propdoc: {
@@ -834,11 +709,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);
});
}
});
@@ -847,68 +722,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);
});
});
}
});
@@ -961,7 +784,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",
@@ -1036,7 +859,7 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
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_Function."
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
@@ -1122,10 +945,6 @@ var AST_NewTarget = DEFNODE("NewTarget", null, {
$documentation: "A reference to new.target"
});
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
$documentation: "The name of a property accessor (setter/getter function)"
}, AST_Symbol);
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
}, AST_Symbol);
@@ -1319,7 +1138,7 @@ TreeWalker.prototype = {
parent: function(n) {
return this.stack[this.stack.length - 2 - (n || 0)];
},
push: function (node) {
push: function(node) {
if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
@@ -1378,16 +1197,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

179
lib/minify.js Normal file
View File

@@ -0,0 +1,179 @@
"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 minify(files, options) {
var warn_function = AST_Node.warn_function;
try {
options = defaults(options, {
compress: {},
ie8: false,
keep_fnames: false,
mangle: {},
output: {},
parse: {},
sourceMap: false,
timings: false,
toplevel: false,
warnings: false,
wrap: false,
}, true);
var timings = options.timings && {
start: Date.now()
};
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: null,
eval: false,
ie8: false,
keep_classnames: false,
keep_fnames: false,
properties: false,
reserved: [],
safari10: false,
toplevel: false,
}, true);
}
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) {
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) {
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 (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
};
};
})();

View File

@@ -53,29 +53,27 @@ function is_some_comments(comment) {
function OutputStream(options) {
options = defaults(options, {
indent_start : 0,
indent_level : 4,
quote_keys : false,
space_colon : true,
ascii_only : false,
ascii_identifiers: undefined,
unescape_regexps : false,
inline_script : false,
width : 80,
max_line_len : false,
beautify : false,
source_map : null,
bracketize : false,
semicolons : true,
comments : false,
shebang : true,
preserve_line : false,
screw_ie8 : true,
preamble : null,
quote_style : 0,
keep_quoted_props: false,
shorthand : undefined,
ecma : 5,
ie8 : false,
indent_level : 4,
indent_start : 0,
inline_script : true,
keep_quoted_props: false,
max_line_len : false,
preamble : null,
preserve_line : false,
quote_keys : false,
quote_style : 0,
semicolons : true,
shebang : true,
shorthand : undefined,
source_map : null,
width : 80,
wrap_iife : false,
}, true);
@@ -155,7 +153,7 @@ function OutputStream(options) {
case "\t": return "\\t";
case "\b": return "\\b";
case "\f": return "\\f";
case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
case "\x0B": return options.ie8 ? "\\x0B" : "\\v";
case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff";
@@ -171,17 +169,6 @@ function OutputStream(options) {
return '"' + str.replace(/\x22/g, '\\"') + '"';
}
function quote_template() {
if (!options.ascii_only) {
str = str.replace(/\\(n|r|u2028|u2029)/g, function(s, c) {
switch(c) {
case "n": return "\n";
case "r": return "\r";
case "u2028": return "\u2028";
case "u2029": return "\u2029";
}
return s;
});
}
return '`' + str.replace(/`/g, '\\`') + '`';
}
if (options.ascii_only) str = to_ascii(str);
@@ -224,23 +211,44 @@ function OutputStream(options) {
var might_need_space = false;
var might_need_semicolon = false;
var might_add_newline = 0;
var last = null;
var last = "";
var mapping_token, mapping_name, mappings = options.source_map && [];
function last_char() {
var char = last.charAt(last.length - 1);
if (is_surrogate_pair_tail(char)) {
return last.charAt(last.length - 2) + char;
}
return char;
};
var do_add_mapping = mappings ? function() {
mappings.forEach(function(mapping) {
try {
options.source_map.add(
mapping.token.file,
mapping.line, mapping.col,
mapping.token.line, mapping.token.col,
!mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: mapping.token.file,
line: mapping.token.line,
col: mapping.token.col,
cline: mapping.line,
ccol: mapping.col,
name: mapping.name || ""
})
}
});
mappings = [];
} : noop;
var ensure_line_len = options.max_line_len ? function() {
if (current_col > options.max_line_len) {
if (might_add_newline) {
var left = OUTPUT.slice(0, might_add_newline);
var right = OUTPUT.slice(might_add_newline);
if (mappings) {
var delta = right.length - current_col;
mappings.forEach(function(mapping) {
mapping.line++;
mapping.col += delta;
});
}
OUTPUT = left + "\n" + right;
current_line++;
current_pos++;
@@ -250,7 +258,10 @@ function OutputStream(options) {
AST_Node.warn("Output exceeds {max_line_len} characters", options);
}
}
might_add_newline = 0;
if (might_add_newline) {
might_add_newline = 0;
do_add_mapping();
}
} : noop;
var requireSemicolonChars = makePredicate("( [ + * / - , .");
@@ -258,10 +269,11 @@ function OutputStream(options) {
function print(str) {
str = String(str);
var ch = get_full_char(str, 0);
var prev = get_full_char(last, last.length - 1);
if (might_need_semicolon) {
might_need_semicolon = false;
if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
if (options.semicolons || requireSemicolonChars(ch)) {
OUTPUT += ";";
current_col++;
@@ -298,7 +310,6 @@ function OutputStream(options) {
}
if (might_need_space) {
var prev = last_char();
if ((is_identifier_char(prev)
&& (is_identifier_char(ch) || ch == "\\"))
|| (ch == "/" && ch == prev)
@@ -310,6 +321,18 @@ function OutputStream(options) {
}
might_need_space = false;
}
if (mapping_token) {
mappings.push({
token: mapping_token,
name: mapping_name,
line: current_line,
col: current_col
});
mapping_token = false;
if (!might_add_newline) do_add_mapping();
}
OUTPUT += str;
current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1;
@@ -405,27 +428,12 @@ function OutputStream(options) {
function colon() {
print(":");
if (options.space_colon) space();
space();
};
var add_mapping = options.source_map ? function(token, name) {
try {
if (token) options.source_map.add(
token.file || "?",
current_line, current_col,
token.line, token.col,
(!name && token.type == "name") ? token.value : name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: token.file,
line: token.line,
col: token.col,
cline: current_line,
ccol: current_col,
name: name || ""
})
}
var add_mapping = mappings ? function(token, name) {
mapping_token = token;
mapping_name = name;
} : noop;
function get() {
@@ -559,8 +567,8 @@ function OutputStream(options) {
}));
}
if (comments.length > 0 && output.pos() == 0) {
if (output.option("shebang") && comments[0].type == "comment5") {
if (output.pos() == 0) {
if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") {
output.print("#!" + comments.shift().value + "\n");
output.indent();
}
@@ -640,7 +648,7 @@ function OutputStream(options) {
return first_in_statement(output);
});
PARENS([ AST_Unary, AST_Undefined ], function(output){
PARENS(AST_Unary, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this
@@ -652,28 +660,19 @@ function OutputStream(options) {
&& this.operator !== "--";
});
PARENS([ AST_Infinity, AST_NaN ], function(output){
PARENS(AST_Sequence, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this
|| p instanceof AST_Unary && p.operator != "+" && p.operator != "-"
|| p instanceof AST_Binary && p.right === this
&& (p.operator == "/" || p.operator == "%");
});
PARENS(AST_Seq, function(output){
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
* ==> 20 (side effect, set a := 10 and b := 20) */
|| p instanceof AST_Arrow // x => (x, x)
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
* ==> 20 (side effect, set a := 10 and b := 20) */
|| p instanceof AST_Arrow // x => (x, x)
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
;
});
@@ -770,7 +769,7 @@ function OutputStream(options) {
}
});
PARENS([ AST_Assign, AST_Conditional ], function (output){
PARENS([ AST_Assign, AST_Conditional ], function(output){
var p = output.parent();
// !(a = false) → true
if (p instanceof AST_Unary)
@@ -1094,7 +1093,7 @@ function OutputStream(options) {
function make_then(self, output) {
var b = self.body;
if (output.option("bracketize")
|| !output.option("screw_ie8") && b instanceof AST_Do)
|| output.option("ie8") && b instanceof AST_Do)
return make_block(b, output);
// The squeezer replaces "block"-s that contain only a single
// statement with the statement itself; technically, the AST
@@ -1242,17 +1241,21 @@ function OutputStream(options) {
output.space();
}
if (self.imported_names) {
output.print("{");
self.imported_names.forEach(function(name_import, i) {
output.space();
name_import.print(output);
if (i < self.imported_names.length - 1) {
output.print(",");
if (self.imported_names.length === 1 && self.imported_names[0].foreign_name.name === "*") {
self.imported_names[0].print(output);
} else {
output.print("{");
self.imported_names.forEach(function (name_import, i) {
output.space();
}
});
output.space();
output.print("}");
name_import.print(output);
if (i < self.imported_names.length - 1) {
output.print(",");
output.space();
}
});
output.space();
output.print("}");
}
}
if (self.imported_name || self.imported_names) {
output.space();
@@ -1366,18 +1369,19 @@ function OutputStream(options) {
AST_Call.prototype._codegen(self, output);
});
AST_Seq.DEFMETHOD("_do_print", function(output){
this.car.print(output);
if (this.cdr) {
output.comma();
if (output.should_break()) {
output.newline();
output.indent();
AST_Sequence.DEFMETHOD("_do_print", function(output){
this.expressions.forEach(function(node, index) {
if (index > 0) {
output.comma();
if (output.should_break()) {
output.newline();
output.indent();
}
}
this.cdr.print(output);
}
node.print(output);
});
});
DEFPRINT(AST_Seq, function(self, output){
DEFPRINT(AST_Sequence, function(self, output){
self._do_print(output);
// var p = output.parent();
// if (p instanceof AST_Statement) {
@@ -1498,10 +1502,24 @@ function OutputStream(options) {
output.space();
}
if (self.extends) {
var parens = (
!(self.extends instanceof AST_SymbolRef)
&& !(self.extends instanceof AST_PropAccess)
&& !(self.extends instanceof AST_ClassExpression)
&& !(self.extends instanceof AST_Function)
);
output.print("extends");
output.space();
if (parens) {
output.print("(");
} else {
output.space();
}
self.extends.print(output);
output.space();
if (parens) {
output.print(")");
} else {
output.space();
}
}
if (self.properties.length > 0) output.with_block(function(){
self.properties.forEach(function(prop, i){
@@ -1526,7 +1544,7 @@ function OutputStream(options) {
&& +key + "" == key)
&& parseFloat(key) >= 0) {
output.print(make_num(key));
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) {
if (quote && output.option("keep_quoted_props")) {
output.print_string(key, quote);
} else {
@@ -1601,7 +1619,6 @@ function OutputStream(options) {
if (self.is_generator) {
output.print("*");
}
output.space();
if (self.key instanceof AST_SymbolMethod) {
self.print_property_name(self.key.name, self.quote, output);
} else {
@@ -1621,24 +1638,7 @@ function OutputStream(options) {
DEFPRINT(AST_SymbolDeclaration, function(self, output){
self._do_print(output);
});
DEFPRINT(AST_Undefined, function(self, output){
output.print("void 0");
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_Infinity, function(self, output){
output.print("1");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_NaN, function(self, output){
output.print("0");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_This, function(self, output){
output.print("this");
});
@@ -1659,45 +1659,14 @@ function OutputStream(options) {
}
});
function regexp_safe_literal(code) {
return [
0x5c , // \
0x2f , // /
0x2e , // .
0x2b , // +
0x2a , // *
0x3f , // ?
0x28 , // (
0x29 , // )
0x5b , // [
0x5d , // ]
0x7b , // {
0x7d , // }
0x24 , // $
0x5e , // ^
0x3a , // :
0x7c , // |
0x21 , // !
0x0a , // \n
0x0d , // \r
0x00 , // \0
0xfeff , // Unicode BOM
0x2028 , // unicode "line separator"
0x2029 , // unicode "paragraph separator"
].indexOf(code) < 0;
};
DEFPRINT(AST_RegExp, function(self, output){
var str = self.getValue().toString();
var regexp = self.getValue();
var str = regexp.toString();
if (regexp.raw_source) {
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
}
if (output.option("ascii_only")) {
str = output.to_ascii(str);
} else if (output.option("unescape_regexps")) {
str = str.split("\\\\").map(function(str){
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
var code = parseInt(s.substr(2), 16);
return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
});
}).join("\\\\");
}
output.print(str);
var p = output.parent();

View File

@@ -118,7 +118,7 @@ var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
var PUNC_AFTER_EXPRESSION = makePredicate(characters(";]),:"));
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:"));
var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
@@ -134,8 +134,17 @@ var UNICODE = {
function get_full_char(str, pos) {
var char = str.charAt(pos);
if (char >= "\ud800" && char <= "\udbff") {
return char + str.charAt(pos + 1);
if (is_surrogate_pair_head(char)) {
var next = str.charAt(pos + 1);
if (is_surrogate_pair_tail(next)) {
return char + next;
}
}
if (is_surrogate_pair_tail(char)) {
var prev = str.charAt(pos - 1);
if (is_surrogate_pair_head(prev)) {
return prev + char;
}
}
return char;
}
@@ -152,8 +161,8 @@ function get_full_char_length(str) {
var surrogates = 0;
for (var i = 0; i < str.length; i++) {
if (str.charCodeAt(i) >= 0xd800 && str.charCodeAt(i) <= 0xdbff) {
if (str.charCodeAt(i + 1) >= 0xdc00 && str.charCodeAt(i + 1) <= 0xdfff) {
if (is_surrogate_pair_head(str.charCodeAt(i))) {
if (is_surrogate_pair_tail(str.charCodeAt(i + 1))) {
surrogates++;
i++;
}
@@ -291,7 +300,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
ch = "\n";
}
} else {
if (is_surrogate_pair_head(ch)) {
if (ch.length > 1) {
++S.pos;
++S.col;
}
@@ -336,7 +345,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value))) ||
(type == "arrow");
prev_was_dot = (type == "punc" && value == ".");
if (type == "punc" && value == ".") {
prev_was_dot = true;
} else if (!is_comment) {
prev_was_dot = false;
}
var ret = {
type : type,
value : value,
@@ -598,31 +611,33 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return name;
});
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
var prev_backslash = false, ch, in_class = false;
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
parse_error("Unexpected line terminator");
} else if (prev_backslash) {
regexp += "\\" + ch;
source += "\\" + ch;
prev_backslash = false;
} else if (ch == "[") {
in_class = true;
regexp += ch;
source += ch;
} else if (ch == "]" && in_class) {
in_class = false;
regexp += ch;
source += ch;
} else if (ch == "/" && !in_class) {
break;
} else if (ch == "\\") {
prev_backslash = true;
} else {
regexp += ch;
source += ch;
}
var mods = read_name();
try {
return token("regexp", new RegExp(regexp, mods));
var regexp = new RegExp(source, mods);
regexp.raw_source = source;
return token("regexp", regexp);
} catch(e) {
parse_error(e.message);
parse_error(e.message);
}
});
@@ -785,8 +800,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
next_token.has_directive = function(directive) {
return S.directives[directive] !== undefined &&
S.directives[directive] > 0;
return S.directives[directive] > 0;
}
return next_token;
@@ -845,15 +859,14 @@ var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "nam
function parse($TEXT, options) {
options = defaults(options, {
strict : false,
filename : null,
toplevel : null,
expression : false,
html5_comments : true,
bare_returns : false,
expression : false,
filename : null,
html5_comments : true,
shebang : true,
cli : false,
});
strict : false,
toplevel : null,
}, true);
var S = {
input : (typeof $TEXT == "string"
@@ -965,28 +978,23 @@ function parse($TEXT, options) {
};
var statement = embed_tokens(function() {
var tmp;
handle_regexp();
switch (S.token.type) {
case "string":
var dir = false;
if (S.in_directives === true) {
if ((is_token(peek(), "punc", ";") || peek().nlb) && S.token.raw.indexOf("\\") === -1) {
if (S.in_directives) {
var token = peek();
if (S.token.raw.indexOf("\\") == -1
&& (token.nlb
|| is_token(token, "eof")
|| is_token(token, "punc", ";")
|| is_token(token, "punc", "}"))) {
S.input.add_directive(S.token.value);
} else {
S.in_directives = false;
}
}
var dir = S.in_directives, stat = simple_statement();
if (dir) {
return new AST_Directive({
start : stat.body.start,
end : stat.body.end,
quote : stat.body.quote,
value : stat.body.value,
});
}
return stat;
return dir ? new AST_Directive(stat.body) : stat;
case "template_head":
case "num":
case "regexp":
@@ -1019,90 +1027,126 @@ function parse($TEXT, options) {
}
case "keyword":
switch (tmp = S.token.value, next(), tmp) {
switch (S.token.value) {
case "break":
next();
return break_cont(AST_Break);
case "continue":
next();
return break_cont(AST_Continue);
case "debugger":
next();
semicolon();
return new AST_Debugger();
case "do":
next();
var body = in_loop(statement);
expect_token("keyword", "while");
var condition = parenthesised();
semicolon(true);
return new AST_Do({
body : in_loop(statement),
condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(true), tmp)
body : body,
condition : condition
});
case "while":
next();
return new AST_While({
condition : parenthesised(),
body : in_loop(statement)
});
case "for":
next();
return for_();
case "class":
next();
return class_(AST_DefClass);
case "function":
next();
return function_(AST_Defun);
case "if":
next();
return if_();
case "return":
if (S.in_function == 0 && !options.bare_returns)
croak("'return' outside of function");
next();
var value = null;
if (is("punc", ";")) {
next();
} else if (!can_insert_semicolon()) {
value = expression(true);
semicolon();
}
return new AST_Return({
value: ( is("punc", ";")
? (next(), null)
: can_insert_semicolon()
? null
: (tmp = expression(true), semicolon(), tmp) )
value: value
});
case "switch":
next();
return new AST_Switch({
expression : parenthesised(),
body : in_loop(switch_body_)
});
case "throw":
next();
if (S.token.nlb)
croak("Illegal newline after 'throw'");
var value = expression(true);
semicolon();
return new AST_Throw({
value: (tmp = expression(true), semicolon(), tmp)
value: value
});
case "try":
next();
return try_();
case "var":
return tmp = var_(), semicolon(), tmp;
next();
var node = var_();
semicolon();
return node;
case "let":
return tmp = let_(), semicolon(), tmp;
next();
var node = let_();
semicolon();
return node;
case "const":
return tmp = const_(), semicolon(), tmp;
next();
var node = const_();
semicolon();
return node;
case "with":
if (S.input.has_directive("use strict")) {
croak("Strict mode may not include a with statement");
}
next();
return new AST_With({
expression : parenthesised(),
body : statement()
});
case "import":
return tmp = import_(), semicolon(), tmp;
next();
var node = import_();
semicolon();
return node;
case "export":
next();
return export_();
}
}
@@ -1228,26 +1272,17 @@ function parse($TEXT, options) {
});
};
var arrow_function = function(args) {
var arrow_function = function(start, argnames) {
if (S.token.nlb) {
croak("Unexpected newline before arrow (=>)");
}
expect_token("arrow", "=>");
var argnames;
if (typeof args.length === 'number') {
argnames = args;
} else {
argnames = args.as_params(croak);
}
var body = is("punc", "{") ?
_function_body(true) :
_function_body(false);
var body = _function_body(is("punc", "{"));
return new AST_Arrow({
start : args.start,
start : start,
end : body.end,
argnames : argnames,
body : body
@@ -1268,7 +1303,7 @@ function parse($TEXT, options) {
unexpected();
var args = parameters();
var body = _function_body(true, is_generator || is_generator_property);
var body = _function_body(true, is_generator || is_generator_property, name, args);
return new ctor({
start : args.start,
end : body.end,
@@ -1571,8 +1606,6 @@ function parse($TEXT, options) {
}
function params_or_seq_() {
var start = S.token
expect("(");
var first = true;
var a = [];
while (!is("punc", ")")) {
@@ -1582,26 +1615,20 @@ function parse($TEXT, options) {
next();
a.push(new AST_Expansion({
start: prev(),
expression: expression(false),
expression: expression(),
end: S.token,
}));
if (!is("punc", ")")) {
unexpected(spread_token);
}
} else {
a.push(expression(false));
a.push(expression());
}
}
var end = S.token
next();
return new AST_ArrowParametersOrSeq({
start: start,
end: end,
expressions: a
});
return a;
}
function _function_body(block, generator) {
function _function_body(block, generator, name, args) {
var loop = S.in_loop;
var labels = S.labels;
var current_generator = S.in_generator;
@@ -1615,6 +1642,10 @@ function parse($TEXT, options) {
if (block) {
S.input.push_directives_stack();
var a = block_();
if (S.input.has_directive("use strict")) {
if (name) strict_verify_symbol(name);
if (args) args.forEach(strict_verify_symbol);
}
S.input.pop_directives_stack();
} else {
var a = expression(false);
@@ -1772,7 +1803,10 @@ function parse($TEXT, options) {
def = new AST_VarDef({
start : S.token,
name : as_symbol(sym_type),
value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
value : is("operator", "=")
? (next(), expression(false, no_in))
: !no_in && kind === "const" && S.input.has_directive("use strict")
? croak("Missing initializer in const declaration") : null,
end : prev()
})
}
@@ -1800,10 +1834,10 @@ function parse($TEXT, options) {
});
};
var const_ = function() {
var const_ = function(no_in) {
return new AST_Const({
start : prev(),
definitions : vardefs(false, "const"),
definitions : vardefs(no_in, "const"),
end : prev()
});
};
@@ -1880,6 +1914,63 @@ function parse($TEXT, options) {
return ret;
};
function to_fun_args(ex, _, __, default_seen_above) {
var insert_default = function(ex, default_value) {
if (default_value) {
return new AST_DefaultAssign({
start: ex.start,
left: ex,
operator: "=",
right: default_value,
end: default_value.end
});
}
return ex;
}
if (ex instanceof AST_Object) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: false,
names: ex.properties.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_ObjectKeyVal) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key]);
}
ex.value = to_fun_args(ex.value, 0, [ex.key]);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Hole) {
return ex;
} else if (ex instanceof AST_Destructuring) {
ex.names = ex.names.map(to_fun_args);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_SymbolRef) {
return insert_default(new AST_SymbolFunarg({
name: ex.name,
start: ex.start,
end: ex.end
}), default_seen_above);
} else if (ex instanceof AST_Expansion) {
ex.expression = to_fun_args(ex.expression);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Array) {
return insert_default(new AST_Destructuring({
start: ex.start,
end: ex.end,
is_array: true,
names: ex.elements.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_Assign) {
return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above);
} else if (ex instanceof AST_DefaultAssign) {
ex.left = to_fun_args(ex.left, 0, [ex.left]);
return ex;
} else {
croak("Invalid function parameter", ex.start.line, ex.start.col);
}
}
var expr_atom = function(allow_calls) {
if (is("operator", "new")) {
return new_(allow_calls);
@@ -1888,13 +1979,15 @@ function parse($TEXT, options) {
if (is("punc")) {
switch (start.value) {
case "(":
var ex = params_or_seq_();
next();
var exprs = params_or_seq_();
expect(")");
if (is("arrow", "=>")) {
ex.start = start;
ex.end = S.token;
return arrow_function(ex);
return arrow_function(start, exprs.map(to_fun_args));
}
ex = ex.as_expr(croak);
var ex = exprs.length == 1 ? exprs[0] : new AST_Sequence({
expressions: exprs
});
ex.start = start;
ex.end = S.token;
return subscripts(ex, allow_calls);
@@ -2176,17 +2269,7 @@ function parse($TEXT, options) {
next();
}
if (is("punc", "{")) {
next();
imported_names = [];
while (!is("punc", "}")) {
imported_names.push(import_name());
if (is("punc", ",")) {
next();
}
}
next();
}
imported_names = import_names(true);
if (imported_names || imported_name) {
expect_token("name", "from");
@@ -2237,16 +2320,14 @@ function parse($TEXT, options) {
})
}
function import_nameAsterisk() {
function import_nameAsterisk(name) {
var start = S.token;
var foreign_name;
var name;
next();
var end = prev();
name = new AST_SymbolImport({
name = name || new AST_SymbolImport({
name: '*',
start: start,
end: end,
@@ -2266,6 +2347,30 @@ function parse($TEXT, options) {
})
}
function import_names(allow_as) {
var names;
if (is("punc", "{")) {
next();
names = [];
while (!is("punc", "}")) {
names.push(import_name());
if (is("punc", ",")) {
next();
}
}
next();
} else if (is("operator", "*")) {
var name;
next();
if (allow_as && is("name", "as")) {
next(); // The "as" word
name = as_symbol(AST_SymbolImportForeign);
}
names = [import_nameAsterisk(name)];
}
return names;
}
function export_() {
var start = S.token;
var is_default;
@@ -2276,54 +2381,64 @@ function parse($TEXT, options) {
if (is("keyword", "default")) {
is_default = true;
next();
}
} else {
exported_names = import_names(false);
if (is("punc", "{")) {
next();
exported_names = [];
while (!is("punc", "}")) {
exported_names.push(import_name());
if (is("punc", ",")) {
if (exported_names) {
if (is("name", "from")) {
next();
var mod_str = S.token;
if (mod_str.type !== 'string') {
unexpected();
}
next();
return new AST_Export({
start: start,
is_default: is_default,
exported_names: exported_names,
module_name: new AST_String({
start: mod_str,
value: mod_str.value,
quote: mod_str.quote,
end: mod_str,
}),
end: prev(),
});
} else {
return new AST_Export({
start: start,
is_default: is_default,
exported_names: exported_names,
end: prev(),
});
}
}
next();
} else if (is("operator", "*")) {
var st = prev();
exported_names = [import_nameAsterisk()];
}
if (exported_names) {
expect_token("name", "from");
var mod_str = S.token;
if (mod_str.type !== 'string') {
unexpected();
}
next();
return new AST_Export({
start: start,
is_default: is_default,
exported_names: exported_names,
module_name: new AST_String({
start: mod_str,
value: mod_str.value,
quote: mod_str.quote,
end: mod_str,
}),
end: prev(),
});
}
var is_definition =
is("keyword", "var") || is("keyword", "let") || is("keyword", "const") ||
is("keyword", "class") || is("keyword", "function");
var is_definition = is("keyword", "var") || is("keyword", "let") || is("keyword", "const");
if (is_definition) {
if (is_default) unexpected();
exported_definition = statement();
} else if (is("keyword", "class")) {
var cls = expr_atom(false);
if (cls.name) {
cls.name = new AST_SymbolDefClass(cls.name);
exported_definition = new AST_DefClass(cls);
} else {
exported_value = cls;
}
} else if (is("keyword", "function")) {
var func = expr_atom(false);
if (func.name) {
func.name = new AST_SymbolDefun(func.name);
exported_definition = new AST_Defun(func);
} else {
exported_value = func;
}
} else {
exported_value = expression();
exported_value = expression(false);
semicolon();
}
@@ -2338,29 +2453,32 @@ function parse($TEXT, options) {
function as_property_name() {
var tmp = S.token;
next();
switch (tmp.type) {
case "punc":
if (tmp.value === "[") {
next();
var ex = expression(false);
expect("]");
return ex;
} else unexpected(tmp);
case "operator":
if (tmp.value === "*") {
next();
return null;
}
if (["delete", "in", "instanceof", "new", "typeof", "void"].indexOf(tmp.value) === -1) {
unexpected(tmp);
}
case "name":
if (tmp.value === "yield" && S.input.has_directive("use strict") && !is_in_generator()) {
if (tmp.value == "yield" && !is_token(peek(), "punc", ":")
&& S.input.has_directive("use strict") && !is_in_generator()) {
token_error(tmp, "Unexpected yield identifier inside strict mode");
}
case "string":
case "num":
case "keyword":
case "atom":
next();
return tmp.value;
default:
unexpected(tmp);
@@ -2369,16 +2487,9 @@ function parse($TEXT, options) {
function as_name() {
var tmp = S.token;
if (tmp.type != "name") unexpected();
next();
switch (tmp.type) {
case "name":
case "operator":
case "keyword":
case "atom":
return tmp.value;
default:
unexpected();
}
return tmp.value;
};
function _make_symbol(type) {
@@ -2392,6 +2503,11 @@ function parse($TEXT, options) {
});
};
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
croak("Unexpected " + sym.name + " in strict mode", sym.start.line, sym.start.col, sym.start.pos);
}
function as_symbol(type, noerror) {
if (!is("name")) {
if (!noerror) croak("Name expected");
@@ -2401,6 +2517,9 @@ function parse($TEXT, options) {
token_error(S.prev, "Unexpected yield identifier inside strict mode");
}
var sym = _make_symbol(type);
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
strict_verify_symbol(sym);
}
next();
return sym;
};
@@ -2470,14 +2589,14 @@ function parse($TEXT, options) {
if (is("operator") && UNARY_PREFIX(start.value)) {
next();
handle_regexp();
var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
ex.start = start;
ex.end = prev();
return ex;
}
var val = expr_atom(allow_calls);
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
val = make_unary(AST_UnaryPostfix, S.token.value, val);
val = make_unary(AST_UnaryPostfix, S.token, val);
val.start = start;
val.end = S.token;
next();
@@ -2485,9 +2604,19 @@ function parse($TEXT, options) {
return val;
};
function make_unary(ctor, op, expr) {
if ((op == "++" || op == "--") && !is_assignable(expr))
croak("Invalid use of " + op + " operator", null, ctor === AST_UnaryPrefix ? expr.start.col - 1 : null);
function make_unary(ctor, token, expr) {
var op = token.value;
switch (op) {
case "++":
case "--":
if (!is_assignable(expr))
croak("Invalid use of " + op + " operator", token.line, token.col, token.pos);
break;
case "delete":
if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos);
break;
}
return new ctor({ operator: op, expression: expr });
};
@@ -2536,7 +2665,6 @@ function parse($TEXT, options) {
};
function is_assignable(expr) {
if (options.cli) return true;
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
};
@@ -2599,7 +2727,7 @@ function parse($TEXT, options) {
if (start.type == "punc" && start.value == "(" && peek().value == ")") {
next();
next();
return arrow_function([]);
return arrow_function(start, []);
}
if (is("name") && is_token(peek(), "arrow")) {
@@ -2609,7 +2737,7 @@ function parse($TEXT, options) {
end: start,
});
next();
return arrow_function([param])
return arrow_function(start, [param]);
}
var left = maybe_conditional(no_in);
@@ -2633,25 +2761,18 @@ function parse($TEXT, options) {
var expression = function(commas, no_in) {
var start = S.token;
var expr = maybe_assign(no_in);
if (expr instanceof AST_SymbolRef && is("arrow", "=>")) {
expr = new AST_ArrowParametersOrSeq({
start: expr.start,
end: expr.end,
expressions: [expr]
});
return arrow_function(expr);
}
if (commas && is("punc", ",")) {
var exprs = [];
while (true) {
exprs.push(maybe_assign(no_in));
if (!commas || !is("punc", ",")) break;
next();
return new AST_Seq({
start : start,
car : expr,
cdr : expression(true, no_in),
end : peek()
});
commas = true;
}
return expr;
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
start : start,
expressions : exprs,
end : peek()
});
};
function in_loop(cont) {

View File

@@ -43,17 +43,26 @@
"use strict";
function find_builtins() {
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[new_global] || new Function();
objects[new_global] = global_ref[new_global] || new Function();
});
var a = [];
// 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, objects.Symbol, ArrayBuffer,
@@ -72,24 +81,23 @@ 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,
cache : null,
only_cache : false,
regex : null,
ignore_quoted : false,
debug : false
builtins: false,
cache: null,
debug: false,
keep_quoted: false,
only_cache: false,
regex: null,
reserved: null,
});
var reserved = options.reserved;
if (reserved == null)
reserved = find_builtins();
var reserved = options.reserved || [];
if (!options.builtins) find_builtins(reserved);
var cache = options.cache;
if (cache == null) {
@@ -100,12 +108,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);
@@ -113,12 +121,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
@@ -128,7 +136,7 @@ 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);
@@ -138,7 +146,7 @@ function mangle_properties(ast, options) {
// 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) {
@@ -149,7 +157,7 @@ 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) {
@@ -174,27 +182,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;
}
@@ -217,19 +224,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);
@@ -237,17 +244,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) {
@@ -265,8 +272,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);
@@ -278,5 +286,4 @@ function mangle_properties(ast, options) {
return node;
}));
}
}

View File

@@ -51,7 +51,6 @@ function SymbolDef(scope, index, orig) {
this.global = false;
this.export = false;
this.mangled_name = null;
this.object_destructuring_arg = false;
this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++;
@@ -65,7 +64,6 @@ SymbolDef.prototype = {
return (this.global && !options.toplevel)
|| this.export
|| this.object_destructuring_arg
|| this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|| (options.keep_fnames
@@ -84,7 +82,7 @@ SymbolDef.prototype = {
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
var sym = this.orig[0];
if (!options.screw_ie8 && sym instanceof AST_SymbolLambda)
if (options.ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
var def;
if (this.defun && (def = this.defun.variables.get(this.name))) {
@@ -100,8 +98,9 @@ SymbolDef.prototype = {
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
@@ -110,8 +109,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var labels = new Dictionary();
var defun = null;
var in_destructuring = null;
var in_export = false;
var in_block = 0;
var for_scopes = [];
var tw = new TreeWalker(function(node, descend){
if (node.is_block_scope()) {
var save_scope = scope;
@@ -122,6 +120,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
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;
@@ -145,22 +148,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
labels = save_labels;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Export) {
in_export = true;
descend();
in_export = false;
return true;
}
if (node instanceof AST_BlockStatement
|| node instanceof AST_Switch
|| node instanceof AST_Try
|| node instanceof AST_Catch
|| node instanceof AST_Finally) {
in_block++;
descend();
in_block--;
return true;
}
if (node instanceof AST_LabeledStatement) {
var l = node.label;
if (labels.has(l.name)) {
@@ -179,15 +166,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
if (node instanceof AST_Symbol) {
node.scope = scope;
}
if (node instanceof AST_SymbolFunarg) {
node.object_destructuring_arg = !!in_destructuring;
}
if (node instanceof AST_Label) {
node.thedef = node;
node.references = [];
}
if (node instanceof AST_SymbolLambda) {
defun.def_function(node, in_export, in_block);
defun.def_function(node);
}
else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is
@@ -199,23 +183,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
while (parent_lambda.is_block_scope()) {
parent_lambda = parent_lambda.parent_scope;
}
(node.scope = parent_lambda).def_function(node, in_export, in_block);
mark_export((node.scope = parent_lambda).def_function(node), 1);
}
else if (node instanceof AST_SymbolClass) {
defun.def_variable(node, in_export, in_block);
mark_export(defun.def_variable(node), 1);
}
else if (node instanceof AST_SymbolImport) {
scope.def_variable(node, in_export, in_block);
scope.def_variable(node);
}
else if (node instanceof AST_SymbolDefClass) {
// This deals with the name of the class being available
// inside the class.
(node.scope = defun.parent_scope).def_function(node, in_export, in_block);
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 = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export, in_block);
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);
@@ -227,7 +212,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}
}
else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node, in_export, in_block).defun = defun;
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
@@ -238,28 +223,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}));
node.thedef = sym;
}
function mark_export(def, level) {
var node = tw.parent(level);
def.export = node instanceof AST_Export && !node.is_default;
}
});
self.walk(tw);
// pass 2: find back references and eval
var func = null;
var cls = 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_Class) {
var prev_cls = cls;
cls = node;
descend();
cls = prev_cls;
return true;
}
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
@@ -286,7 +260,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
self.walk(tw);
// pass 3: fix up any scoping issue with IE8
if (!options.screw_ie8) {
if (options.ie8) {
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) {
var name = node.name;
@@ -303,6 +277,19 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}));
}
// 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;
}
@@ -331,27 +318,18 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.cname = -1; // the current index for mangling functions/variables
});
AST_Node.DEFMETHOD("is_block_scope", function(){
return false; // Behaviour will be overridden by AST_Block
});
AST_Block.DEFMETHOD("is_block_scope", function(){
return (
!(this instanceof AST_Lambda) &&
!(this instanceof AST_Toplevel) &&
!(this instanceof AST_Class) &&
!(this instanceof AST_SwitchBranch)
);
});
AST_IterationStatement.DEFMETHOD("is_block_scope", function(){
return true;
});
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;
this.def_variable(new AST_SymbolVar({
this.def_variable(new AST_SymbolConst({
name: "arguments",
start: this.start,
end: this.end
@@ -384,24 +362,18 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
AST_Scope.DEFMETHOD("def_function", function(symbol, in_export, in_block){
this.functions.set(symbol.name, this.def_variable(symbol, in_export, in_block));
AST_Scope.DEFMETHOD("def_function", function(symbol){
var def = this.def_variable(symbol);
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export, in_block){
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
def.object_destructuring_arg = symbol.object_destructuring_arg;
if (in_export) {
def.export = true;
}
if (in_block && symbol instanceof AST_SymbolBlockDeclaration) {
def.global = false;
} else {
def.global = !this.parent_scope;
}
def.global = !this.parent_scope;
} else {
def = this.variables.get(symbol.name);
def.orig.push(symbol);
@@ -416,8 +388,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
@@ -453,15 +425,8 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
return def && def.unmangleable(options);
});
// property accessors are not mangleable
AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
return true;
});
// 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
@@ -472,13 +437,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;
@@ -490,13 +451,12 @@ AST_Symbol.DEFMETHOD("global", function(){
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
return defaults(options, {
except : [],
eval : false,
sort : false, // Ignored. Flag retained for backwards compatibility.
toplevel : false,
screw_ie8 : true,
ie8 : false,
keep_classnames: false,
keep_fnames : false,
keep_classnames : false
reserved : [],
toplevel : false,
});
});
@@ -504,7 +464,7 @@ 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
@@ -515,7 +475,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);
}
});
@@ -532,7 +492,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);
}
});
@@ -546,7 +506,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true;
}
var mangle_with_block_scope =
(options.screw_ie8 && node instanceof AST_SymbolCatch) ||
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
to_mangle.push(node.definition());
@@ -555,7 +515,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
});
this.walk(tw);
to_mangle.forEach(function(def){
if (def.destructuring && !def.destructuring.is_array) return;
def.mangle(options);
});
@@ -678,89 +637,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

@@ -182,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){
@@ -240,6 +239,11 @@ TreeTransformer.prototype = new TreeWalker;
self.expression = self.expression.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);
});
_(AST_TemplateString, function(self, tw) {
for (var i = 0; i < self.segments.length; i++) {
if (!(self.segments[i] instanceof AST_TemplateSegment)) {

View File

@@ -346,7 +346,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.19",
"version": "3.0.14",
"engines": {
"node": ">=0.8.0"
},
@@ -29,26 +29,16 @@
"LICENSE"
],
"dependencies": {
"source-map": "~0.5.1",
"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"
},
"optionalDependencies": {
"uglify-to-browserify": "~1.0.0"
},
"browserify": {
"transform": [
"uglify-to-browserify"
]
"acorn": "~5.0.3",
"mocha": "~2.3.4",
"semver": "~5.3.0"
},
"scripts": {
"test": "node test/run-tests.js"
},
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
"keywords": ["uglify", "uglify-js", "uglify-es", "minify", "minifier", "es5", "es6", "es2015"]
}

View File

@@ -7,12 +7,12 @@ var createHash = require("crypto").createHash;
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",
@@ -30,11 +30,6 @@ function done() {
console.log();
console.log(url);
console.log(info.log);
var elapsed = 0;
info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) {
elapsed += parseFloat(time);
});
console.log("Run-time:", elapsed.toFixed(3), "s");
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("SHA1 sum:", info.sha1);

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

@@ -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\'}'
}

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

View File

@@ -2,7 +2,7 @@ collapse_vars_side_effects_1: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1() {
@@ -68,11 +68,10 @@ collapse_vars_side_effects_1: {
log(x, s.charAt(i++), y, 7);
}
function f4() {
var log = console.log.bind(console),
i = 10,
var i = 10,
x = i += 2,
y = i += 3;
log(x, i += 4, y, i);
console.log.bind(console)(x, i += 4, y, i);
}
f1(), f2(), f3(), f4();
}
@@ -151,7 +150,7 @@ collapse_vars_issue_721: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
define(["require", "exports", 'handlebars'], function (require, exports, hb) {
@@ -217,7 +216,7 @@ collapse_vars_properties: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1(obj) {
@@ -244,7 +243,7 @@ collapse_vars_if: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1() {
@@ -294,7 +293,7 @@ collapse_vars_while: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1(y) {
@@ -393,9 +392,9 @@ collapse_vars_do_while: {
}
function f3(y) {
function fn(n) { console.log(n); }
var a = 2;
var a = 2, x = 7;
do {
fn(a = 7);
fn(a = x);
break;
} while (y);
}
@@ -468,8 +467,9 @@ collapse_vars_do_while_drop_assign: {
}
function f3(y) {
function fn(n) { console.log(n); }
var x = 7;
do {
fn(7);
fn(x);
break;
} while (y);
}
@@ -670,8 +670,8 @@ collapse_vars_lvalues: {
function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var w = e1(), v = e2(), c = v = --x; return (w = x) - c; }
function f6(x) { var w = e1(), v = e2(); return (v = --x) - (w = x); }
function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; }
function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); }
function f7(x) { var w = e1(); return (w = x) - (e2() - x); }
function f8(x) { var w = e1(); return (w = x) - (e2() - x); }
function f9(x) { var w = e1(); return e2() - x - (w = x); }
}
}
@@ -700,10 +700,10 @@ collapse_vars_lvalues_drop_assign: {
function f2(x) { var z = x, a = ++z; return z += a; }
function f3(x) { var a = (x -= 3); return x + a; }
function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; }
function f5(x) { e1(); var v = e2(), c = v = --x; return x - c; }
function f6(x) { e1(), e2(); return --x - x; }
function f7(x) { var v = (e1(), e2()), c = v - x; return x - c; }
function f8(x) { var v = (e1(), e2()); return x - (v - x); }
function f7(x) { e1(); return x - (e2() - x); }
function f8(x) { e1(); return x - (e2() - x); }
function f9(x) { e1(); return e2() - x - x; }
}
}
@@ -712,7 +712,7 @@ collapse_vars_misc1: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f0(o, a, h) {
@@ -789,7 +789,7 @@ collapse_vars_repeated: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1() {
@@ -812,19 +812,17 @@ collapse_vars_repeated: {
}
expect: {
function f1() {
return -3
return -3;
}
function f2(x) {
return x
return x;
}
(function(x){
var a = "GOOD" + x, e = "BAD", e = a;
console.log(e + "!");
})("!"),
console.log("GOOD!!");
})(),
(function(x){
var a = "GOOD" + x, e = "BAD" + x, e = a;
console.log(e + "!");
})("!");
console.log("GOOD!!");
})();
}
expect_stdout: true
}
@@ -833,7 +831,7 @@ collapse_vars_closures: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function constant_vars_can_be_replaced_in_any_scope() {
@@ -923,7 +921,7 @@ collapse_vars_try: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1() {
@@ -1048,10 +1046,9 @@ collapse_vars_object: {
}
expect: {
function f0(x, y) {
var z = x + y;
return {
get b() { return 7; },
r: z
r: x + y
};
}
function f1(x, y) {
@@ -1121,7 +1118,7 @@ collapse_vars_constants: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, reduce_vars:true
}
input: {
function f1(x) {
@@ -1159,7 +1156,7 @@ collapse_vars_arguments: {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
toplevel:true
toplevel:true, reduce_vars:true
}
input: {
var outer = function() {
@@ -1286,6 +1283,7 @@ collapse_vars_regexp: {
join_vars: true,
cascade: true,
side_effects: true,
reduce_vars: true,
}
input: {
function f1() {
@@ -1319,8 +1317,8 @@ collapse_vars_regexp: {
};
}
(function(){
var result, s = "acdabcdeabbb", rx = /ab*/g;
while (result = rx.exec(s))
var result, rx = /ab*/g;
while (result = rx.exec("acdabcdeabbb"))
console.log(result[0]);
})();
}
@@ -1367,8 +1365,8 @@ issue_1537_destructuring_1: {
[x] = [y];
}
expect: {
var x = 1;
[x] = [2];
var x = 1, y = 2;
[x] = [y];
}
}
@@ -1443,7 +1441,10 @@ issue_1537_destructuring_for_of: {
issue_1562: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var v = 1, B = 2;
@@ -1462,14 +1463,11 @@ issue_1562: {
var v = 1;
for (v in objs) f(2);
var x = 3;
while(x + 2) bar(10);
while(5) bar(10);
var y = 4;
do bar(20); while(y + 2);
do bar(20); while(6);
var z = 5;
for (; f(z + 2) ;) bar(30);
for (; f(7) ;) bar(30);
}
}
@@ -1672,6 +1670,7 @@ var_side_effects_3: {
options = {
collapse_vars: true,
pure_getters: true,
unsafe: true,
}
input: {
var print = console.log.bind(console);
@@ -1690,3 +1689,644 @@ var_side_effects_3: {
}
expect_stdout: true
}
reduce_vars_assign: {
options = {
collapse_vars: true,
reduce_vars: true,
}
input: {
!function() {
var a = 1;
a = [].length,
console.log(a);
}();
}
expect: {
!function() {
var a = 1;
a = [].length,
console.log(a);
}();
}
expect_stdout: "0"
}
iife_1: {
options = {
collapse_vars: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var log = function(x) {
console.log(x);
}, foo = bar();
log(foo);
}
expect: {
(function(x) {
console.log(x);
})(bar());
}
}
iife_2: {
options = {
collapse_vars: true,
reduce_vars: false,
toplevel: true,
unused: false,
}
input: {
var foo = bar();
!function(x) {
console.log(x);
}(foo);
}
expect: {
!function(x) {
console.log(x);
}(bar());
}
}
var_defs: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
}
input: {
var f1 = function(x, y) {
var a, b, r = x + y, q = r * r, z = q - r, a = z, b = 7;
console.log(a + b);
};
f1("1", 0);
}
expect: {
var f1 = function(x, y) {
var r = x + y, a = r * r - r, b = 7;
console.log(a + b);
};
f1("1", 0);
}
expect_stdout: "97"
}
assignment: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f() {
var a;
a = x;
return a;
}
}
expect: {
function f() {
return x;
}
}
}
for_init: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(x, y) {
var a = x;
var b = y;
for (a; b;);
}
}
expect: {
function f(x, y) {
var b = y;
for (x; b;);
}
}
}
switch_case: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(x, y, z) {
var a = x();
var b = y();
var c = z;
switch (a) {
default: d();
case b: e();
case c: f();
}
}
}
expect: {
function f(x, y, z) {
var c = z;
switch (x()) {
default: d();
case y(): e();
case c: f();
}
}
}
}
issue_27: {
options = {
collapse_vars: true,
unused: true,
}
input: {
(function(jQuery) {
var $;
$ = jQuery;
$("body").addClass("foo");
})(jQuery);
}
expect: {
(function(jQuery) {
jQuery("body").addClass("foo");
})(jQuery);
}
}
modified: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f1(b) {
var a = b;
return b + a;
}
function f2(b) {
var a = b;
return b++ + a;
}
function f3(b) {
var a = b++;
return b + a;
}
function f4(b) {
var a = b++;
return b++ + a;
}
function f5(b) {
var a = function() {
return b;
}();
return b++ + a;
}
console.log(f1(1), f2(1), f3(1), f4(1), f5(1));
}
expect: {
function f1(b) {
return b + b;
}
function f2(b) {
var a = b;
return b++ + a;
}
function f3(b) {
var a = b++;
return b + a;
}
function f4(b) {
var a = b++;
return b++ + a;
}
function f5(b) {
var a = function() {
return b;
}();
return b++ + a;
}
console.log(f1(1), f2(1), f3(1), f4(1), f5(1));
}
expect_stdout: "2 2 3 3 2"
}
issue_1858: {
options = {
collapse_vars: true,
pure_getters: true,
unused: true,
}
input: {
console.log(function(x) {
var a = {}, b = a.b = x;
return a.b + b;
}(1));
}
expect: {
console.log(function(x) {
var a = {}, b = a.b = x;
return a.b + b;
}(1));
}
expect_stdout: "2"
}
anonymous_function: {
options = {
collapse_vars: true,
}
input: {
console.log(function f(a) {
f ^= 0;
return f * a;
}(1));
}
expect: {
console.log(function f(a) {
f ^= 0;
return f * a;
}(1));
}
expect_stdout: true
}
side_effects_property: {
options = {
collapse_vars: true,
}
input: {
var a = [];
var b = 0;
a[b++] = function() { return 42;};
var c = a[b++]();
console.log(c);
}
expect: {
var a = [];
var b = 0;
a[b++] = function() { return 42;};
var c = a[b++]();
console.log(c);
}
expect_stdout: true
}
undeclared: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(x, y) {
var a;
a = x;
b = y;
return b + a;
}
}
expect: {
function f(x, y) {
var a;
a = x;
b = y;
return b + a;
}
}
}
ref_scope: {
options = {
collapse_vars: 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 function() {
return a;
}() + b;
}());
}
expect_stdout: true
}
chained_1: {
options = {
collapse_vars: true,
}
input: {
var a = 2;
var a = 3 / a;
console.log(a);
}
expect: {
var a = 3 / (a = 2);
console.log(a);
}
expect_stdout: true
}
chained_2: {
options = {
collapse_vars: true,
}
input: {
var a;
var a = 2;
a = 3 / a;
console.log(a);
}
expect: {
var a;
a = 3 / (a = 2);
console.log(a);
}
expect_stdout: true
}
chained_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a, b) {
var c = a, c = b;
b++;
return c;
}(1, 2));
}
expect: {
console.log(function(a, b) {
var c = a, c = b;
b++;
return c;
}(1, 2));
}
expect_stdout: "2"
}
boolean_binary_1: {
options = {
collapse_vars: true,
}
input: {
var a = 1;
a++;
(function() {} || a || 3).toString();
console.log(a);
}
expect: {
var a = 1;
a++;
(function() {} || a || 3).toString();
console.log(a);
}
expect_stdout: true
}
boolean_binary_2: {
options = {
collapse_vars: true,
}
input: {
var c = 0;
c += 1;
(function() {
c = 1 + c;
} || 9).toString();
console.log(c);
}
expect: {
var c = 0;
c += 1;
(function() {
c = 1 + c;
} || 9).toString();
console.log(c);
}
expect_stdout: true
}
inner_lvalues: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var a, b = 10;
var a = (--b || a || 3).toString(), c = --b + -a;
console.log(null, a, b);
}
expect: {
var a, b = 10;
var a = (--b || a || 3).toString(), c = --b + -a;
console.log(null, a, b);
}
expect_stdout: true
}
double_def: {
options = {
collapse_vars: true,
}
input: {
var a = x, a = a && y;
a();
}
expect: {
var a = x;
(a = a && y)();
}
}
toplevel_single_reference: {
options = {
collapse_vars: true,
}
input: {
var a;
for (var b in x) {
var a = b;
b(a);
}
}
expect: {
var a;
for (var b in x)
b(a = b);
}
}
unused_orig: {
options = {
collapse_vars: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
var a = 1;
console.log(function(b) {
var a;
var c = b;
for (var d in c) {
var a = c[0];
return --b + a;
}
try {
} catch (e) {
--b + a;
}
a && a.NaN;
}([2]), a);
}
expect: {
var a = 1;
console.log(function(b) {
var a;
var c = b;
for (var d in c)
return --b + (a = c[0]);
a && a.NaN;
}([2]), a);
}
expect_stdout: "3 1"
}
issue_315: {
options = {
collapse_vars: true,
evaluate: true,
keep_fargs: false,
reduce_vars: true,
sequences: true,
unused: true,
}
input: {
console.log(function(s) {
var w, _i, _len, _ref, _results;
_ref = s.trim().split(" ");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
w = _ref[_i];
_results.push(w.toLowerCase());
}
return _results;
}("test"));
}
expect: {
console.log(function() {
var w, _i, _len, _ref, _results;
for (_results = [], _i = 0, _len = (_ref = "test".trim().split(" ")).length; _i < _len ; _i++)
w = _ref[_i], _results.push(w.toLowerCase());
return _results;
}());
}
expect_stdout: true
}
lvalues_def: {
options = {
collapse_vars: true,
side_effects: true,
unused: true,
}
input: {
var a = 0, b = 1;
var a = b++, b = +function() {}();
a && a[a++];
console.log(a, b);
}
expect: {
var a = 0, b = 1;
var a = b++, b = +void 0;
a && a[a++];
console.log(a, b);
}
expect_stdout: true
}
compound_assignment: {
options = {
collapse_vars: true,
}
input: {
var a;
a = 1;
a += a + 2;
console.log(a);
}
expect: {
var a;
a = 1;
a += a + 2;
console.log(a);
}
expect_stdout: "4"
}
reassign_const_1: {
options = {
collapse_vars: true,
}
input: {
function f() {
const a = 1;
a = 2;
return a;
}
console.log(f());
}
expect: {
function f() {
const a = 1;
a = 2;
return a;
}
console.log(f());
}
expect_stdout: true
}
reassign_const_2: {
options = {
collapse_vars: true,
}
input: {
function f() {
const a = 1;
++a;
return a;
}
console.log(f());
}
expect: {
function f() {
const a = 1;
++a;
return a;
}
console.log(f());
}
expect_stdout: true
}

View File

@@ -840,8 +840,8 @@ equality_conditionals_false: {
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(0/0),
f(0/0, "foo");
f(NaN),
f(NaN, "foo");
}
expect_stdout: true
}
@@ -888,8 +888,8 @@ equality_conditionals_true: {
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(0/0),
f(0/0, "foo");
f(NaN),
f(NaN, "foo");
}
expect_stdout: true
}
@@ -962,3 +962,56 @@ condition_symbol_matches_consequent: {
}
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

@@ -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;
function g(){};
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,16 +122,55 @@ 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: {
@@ -134,7 +217,7 @@ dead_code_const_declaration: {
var unused;
const CONST_FOO = !1;
var moo;
function bar() {}
var bar;
}
expect_stdout: true
}
@@ -162,7 +245,7 @@ dead_code_const_annotation: {
var unused;
var CONST_FOO_ANN = !1;
var moo;
function bar() {}
var bar;
}
expect_stdout: true
}
@@ -229,7 +312,7 @@ 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';
@@ -278,3 +361,19 @@ try_catch_finally: {
"1",
]
}
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}

View File

@@ -151,8 +151,12 @@ destructuring_remove_unused_1: {
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;
f(b, c);
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
expect: {
@@ -178,8 +182,12 @@ destructuring_remove_unused_1: {
}
function e() {
var a = [1, 2, 3, 4, 5];
var x = [[1, 2, 3]];
var y = {h: 1};
var [b, ...c] = a;
f(b, c);
var [...[e, f]] = x;
var [...{g: h}] = y;
f(b, c, e, f, g);
}
}
}
@@ -307,3 +315,283 @@ unused: {
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: a = 9, o: c, r: l} = e;
console.log(n, o, s, a, c, l);
}
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 n(n) {
let t, a, c;
let l = n.a || { e: 7, n: 8 };
({t: o, e, n: s, s: t = 9, o: a, r: c} = l);
console.log(o, e, s, t, a, c);
}
let o, e, s;
n({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
n({});
}
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, a, c;
let l = o.a || { e: 7, n: 8 };
({t, e, n, s = 9, o: a, r: c} = l);
console.log(t, e, n, s, a, c);
}
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: n = 2}, [a = 3, b = 4]) => {
console.log(o, n, a, b);
})({bar: 5}, [, 6]);
}
expect_stdout: "1 5 3 6"
node_version: ">=6"
}

View File

@@ -1016,7 +1016,8 @@ issue_1715_3: {
try {
console;
} catch (a) {
var a = x();
var a;
x();
}
}
f();
@@ -1055,3 +1056,227 @@ issue_1715_4: {
}
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"
}

View File

@@ -52,7 +52,7 @@ and: {
a = 7;
a = false;
a = 0/0;
a = NaN;
a = 0;
a = void 0;
a = null;
@@ -67,7 +67,7 @@ and: {
a = 6 << condition && -4.5;
a = condition && false;
a = console.log("b") && 0/0;
a = console.log("b") && NaN;
a = console.log("c") && 0;
a = 2 * condition && void 0;
a = condition + 3 && null;
@@ -149,7 +149,7 @@ or: {
a = 6 << condition || -4.5;
a = condition || false;
a = console.log("b") || 0/0;
a = console.log("b") || NaN;
a = console.log("c") || 0;
a = 2 * condition || void 0;
a = condition + 3 || null;
@@ -302,13 +302,13 @@ pow_with_number_constants: {
var m = 3 ** -10; // Result will be 0.000016935087808430286, which is too long
}
expect: {
var a = 0/0;
var a = NaN;
var b = 1;
var c = 1;
var d = 0/0;
var d = NaN;
var e = 1/0;
var f = 0;
var g = 0/0;
var g = NaN;
var h = 1/0;
var i = -1/0;
var j = .125;
@@ -627,7 +627,7 @@ unsafe_array: {
[1, 2, 3, a][0] + 1,
2,
3,
0/0,
NaN,
"1,21",
5,
(void 0)[1] + 1
@@ -896,3 +896,237 @@ issue_1649: {
}
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"
}

View File

@@ -21,13 +21,12 @@ pow_with_number_constants: {
var f = 2 ** -Infinity;
}
expect: {
// TODO: may need parentheses
var a = 5 ** 0/0;
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = 0/0 ** 1;
var e = 2 ** 1/0;
var f = 2 ** -1/0;
var d = NaN ** 1;
var e = 2 ** (1/0);
var f = 2 ** (-1/0);
}
}

View File

@@ -93,3 +93,177 @@ issue_485_crashing_1530: {
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,
}
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("a", "b", "b.exports=42");
fn(null, m, m.exports);
console.log(m.exports);
}
expect_stdout: "42"
}

View File

@@ -145,3 +145,32 @@ 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);
}
}

View File

@@ -152,6 +152,13 @@ class_methods_and_getters_with_keep_quoted_props_enabled: {
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;
@@ -184,19 +191,78 @@ import_statement: {
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\";"
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;
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 1;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: {
@@ -204,8 +270,9 @@ export_module_statement: {
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";'
expect_exact: 'export*from"a.js";export{A}from"a.js";export{A,B}from"a.js";export{C};'
}
import_statement_mangling: {
@@ -305,11 +372,25 @@ default_assign: {
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);
};
}
}
@@ -340,3 +421,201 @@ issue_1613: {
}
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 n of [ 6, 5 ])
for (let r of [ 4, 3 ])
for (var o of [ 2, 1 ])
console.log(n, 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 a = [];
for (let s = 0; s < 6; s++)
a.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 a = [];
for (let r = 0; r < 6; r++)
a.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"
}

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

@@ -116,3 +116,137 @@ non_hoisted_function_after_return_2b: {
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
]
}
non_hoisted_function_after_return_strict: {
options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true
}
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

@@ -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,6 +193,7 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
cascade: true,
side_effects: true,
sequences: false,
keep_infinity: false,
}
input: {
var f = console.log;
@@ -224,10 +225,73 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
};
if (o) {
f(void 0, void 0);
f(0/0, 0/0);
f(NaN, NaN);
f(1/0, 1/0);
f(-1/0, -1/0);
f(0/0, 0/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
}
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);

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

@@ -1,6 +1,6 @@
issue_1321_no_debug: {
mangle_props = {
ignore_quoted: true
keep_quoted: true
}
input: {
var x = {};
@@ -19,7 +19,7 @@ issue_1321_no_debug: {
issue_1321_debug: {
mangle_props = {
ignore_quoted: true,
keep_quoted: true,
debug: ""
}
input: {
@@ -39,7 +39,7 @@ issue_1321_debug: {
issue_1321_with_quoted: {
mangle_props = {
ignore_quoted: false
keep_quoted: false
}
input: {
var x = {};

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

@@ -1,9 +1,9 @@
screw_ie8: {
options = {
screw_ie8: true,
ie8: false,
}
mangle = {
screw_ie8: true,
ie8: false,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
@@ -16,10 +16,10 @@ screw_ie8: {
support_ie8: {
options = {
screw_ie8: false,
ie8: true,
}
mangle = {
screw_ie8: false,
ie8: true,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }

View File

@@ -18,9 +18,7 @@ chained_evaluation_1: {
expect: {
(function() {
(function() {
var c;
c = f(1);
c.bar = 1;
f(1).bar = 1;
})();
})();
}
@@ -45,11 +43,9 @@ chained_evaluation_2: {
}
expect: {
(function() {
var a = "long piece of string";
(function() {
var c;
c = f(a);
c.bar = a;
var b = "long piece of string";
f(b).bar = b;
})();
})();
}

View File

@@ -35,11 +35,11 @@ f7: {
console.log(a, b);
}
expect_exact: [
"var a = 100, b = 10;",
"var b = 10;",
"",
"!function() {",
" for (;b = a, !1; ) ;",
"}(), console.log(a, b);",
" for (;b = 100, !1; ) ;",
"}(), console.log(100, b);",
]
expect_stdout: true
}

View File

@@ -1,10 +1,10 @@
mangle_catch: {
options = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
input: {
@@ -22,11 +22,11 @@ mangle_catch: {
mangle_catch_ie8: {
options = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
input: {
@@ -44,11 +44,11 @@ mangle_catch_ie8: {
mangle_catch_var: {
options = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
input: {
@@ -66,11 +66,11 @@ mangle_catch_var: {
mangle_catch_var_ie8: {
options = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
input: {
@@ -88,11 +88,11 @@ mangle_catch_var_ie8: {
mangle_catch_toplevel: {
options = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
input: {
@@ -110,11 +110,11 @@ mangle_catch_toplevel: {
mangle_catch_ie8_toplevel: {
options = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
input: {
@@ -132,11 +132,11 @@ mangle_catch_ie8_toplevel: {
mangle_catch_var_toplevel: {
options = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
input: {
@@ -154,11 +154,11 @@ mangle_catch_var_toplevel: {
mangle_catch_var_ie8_toplevel: {
options = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
input: {
@@ -176,11 +176,11 @@ mangle_catch_var_ie8_toplevel: {
mangle_catch_redef_1: {
options = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
input: {
@@ -198,11 +198,11 @@ mangle_catch_redef_1: {
mangle_catch_redef_1_ie8: {
options = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
input: {
@@ -220,11 +220,11 @@ mangle_catch_redef_1_ie8: {
mangle_catch_redef_1_toplevel: {
options = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
input: {
@@ -242,11 +242,11 @@ mangle_catch_redef_1_toplevel: {
mangle_catch_redef_1_ie8_toplevel: {
options = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
input: {
@@ -264,11 +264,11 @@ mangle_catch_redef_1_ie8_toplevel: {
mangle_catch_redef_2: {
options = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: false,
}
input: {
@@ -285,11 +285,11 @@ mangle_catch_redef_2: {
mangle_catch_redef_2_ie8: {
options = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: false,
}
input: {
@@ -306,11 +306,11 @@ mangle_catch_redef_2_ie8: {
mangle_catch_redef_2_toplevel: {
options = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: true,
ie8: false,
toplevel: true,
}
input: {
@@ -327,11 +327,11 @@ mangle_catch_redef_2_toplevel: {
mangle_catch_redef_2_ie8_toplevel: {
options = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: false,
ie8: true,
toplevel: true,
}
input: {

View File

@@ -1,6 +1,6 @@
function_iife_catch: {
mangle = {
screw_ie8: true,
ie8: false,
}
input: {
function f(n) {
@@ -21,7 +21,7 @@ function_iife_catch: {
function_iife_catch_ie8: {
mangle = {
screw_ie8: false,
ie8: true,
}
input: {
function f(n) {
@@ -42,7 +42,7 @@ function_iife_catch_ie8: {
function_catch_catch: {
mangle = {
screw_ie8: true,
ie8: false,
}
input: {
var o = 0;
@@ -70,7 +70,7 @@ function_catch_catch: {
function_catch_catch_ie8: {
mangle = {
screw_ie8: false,
ie8: true,
}
input: {
var o = 0;

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,',
' a: 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["a"], 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,15 @@
unary_prefix: {
options = {
evaluate: 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(){};"
}
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(){};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(){};"
}
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{};"
}
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{};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{};"
}
export_mangle_1: {
mangle = {
toplevel: true,
}
input: {
export function foo(one, two) {
return one - two;
};
}
expect_exact: "export function foo(n,o){return n-o};"
}
export_mangle_2: {
mangle = {
toplevel: true,
}
input: {
export default function foo(one, two) {
return one - two;
};
}
expect_exact: "export default function n(n,r){return n-r};"
}
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(n,r){return n-r+n}};"
}
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 n{go(n,r){return n-r+n}};"
}
export_mangle_5: {
mangle = {
toplevel: true,
}
input: {
export default {
prop: function(one, two) {
return one - two;
}
};
}
expect_exact: "export default{prop:function(n,r){return n-r}};"
}
export_mangle_6: {
mangle = {
toplevel: true,
}
input: {
var baz = 2;
export let foo = 1, bar = baz;
}
expect_exact: "var a=2;export let foo=1,bar=a;"
}
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(){};
}
}
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 {};
}
}
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

@@ -1,7 +1,8 @@
compress_new_function: {
options = {
unsafe: true
unsafe: true,
unsafe_Func: true,
}
input: {
new Function("aa, bb", 'return aa;');
@@ -14,6 +15,7 @@ compress_new_function: {
compress_new_function_with_destruct: {
options = {
unsafe: true,
unsafe_Func: true,
ecma: 6
}
beautify = {
@@ -26,9 +28,7 @@ compress_new_function_with_destruct: {
}
expect: {
Function("a", "[b]", "return a");
Function("a", "{bb}", "return a");
Function("[[a]]", "[{bb}]", 'return a');
Function("a", "{bb:b}", "return a");
Function("[[a]]", "[{bb:b}]", 'return a');
}
}

View File

@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
}
expect: {
(1/0).toString();
(0/0).toString();
NaN.toString();
}
}
@@ -24,6 +24,36 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
}
}
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,

View File

@@ -159,7 +159,7 @@ negate_iife_4: {
})();
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false), function(){
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
@@ -183,7 +183,7 @@ negate_iife_5: {
})();
}
expect: {
(function(){ return t })() ? foo(true) : bar(false), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
@@ -207,7 +207,7 @@ negate_iife_5_off: {
})();
}
expect: {
(function(){ return t })() ? foo(true) : bar(false), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}

View File

@@ -215,8 +215,7 @@ evaluate: {
a();
for(;;)
c();
// rule disabled due to issue_1532
do d(); while (false);
d();
}
}
@@ -246,7 +245,7 @@ issue_1532: {
issue_186: {
beautify = {
beautify: false,
screw_ie8: true,
ie8: false,
}
input: {
var x = 3;
@@ -265,7 +264,7 @@ issue_186: {
issue_186_ie8: {
beautify = {
beautify: false,
screw_ie8: false,
ie8: true,
}
input: {
var x = 3;
@@ -284,7 +283,7 @@ issue_186_ie8: {
issue_186_beautify: {
beautify = {
beautify: true,
screw_ie8: true,
ie8: false,
}
input: {
var x = 3;
@@ -311,7 +310,7 @@ issue_186_beautify: {
issue_186_beautify_ie8: {
beautify = {
beautify: true,
screw_ie8: false,
ie8: true,
}
input: {
var x = 3;
@@ -341,7 +340,7 @@ issue_186_bracketize: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: true,
ie8: false,
}
input: {
var x = 3;
@@ -361,7 +360,7 @@ issue_186_bracketize_ie8: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: false,
ie8: true,
}
input: {
var x = 3;
@@ -381,7 +380,7 @@ issue_186_beautify_bracketize: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: true,
ie8: false,
}
input: {
var x = 3;
@@ -413,7 +412,7 @@ issue_186_beautify_bracketize_ie8: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: false,
ie8: true,
}
input: {
var x = 3;
@@ -458,3 +457,26 @@ issue_1648: {
}
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

@@ -25,11 +25,9 @@ negate_iife_2: {
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: {
@@ -38,11 +36,9 @@ negate_iife_2_side_effects: {
side_effects: true,
}
input: {
(function(){ return {} })().x = 10; // should not transform this one
}
expect: {
(function(){ return {} })().x = 10;
}
expect_exact: "({}).x=10;"
}
negate_iife_3: {

View File

@@ -0,0 +1,12 @@
eval_let: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: ""
node_version: ">=6"
}

View File

@@ -186,7 +186,7 @@ unary_binary_parenthesis: {
});
}
expect: {
var v = [ 0, 1, 0/0, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
var v = [ 0, 1, NaN, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
v.forEach(function(x) {
v.forEach(function(y) {
console.log(

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";
@@ -77,7 +77,7 @@ sub_properties: {
a[3.14] = 3;
a.if = 4;
a["foo bar"] = 5;
a[0/0] = 6;
a[NaN] = 6;
a[null] = 7;
a[void 0] = 8;
}
@@ -125,7 +125,7 @@ evaluate_string_length: {
mangle_properties: {
mangle_props = {
ignore_quoted: false
keep_quoted: false
};
input: {
a["foo"] = "bar";
@@ -148,8 +148,8 @@ mangle_unquoted_properties: {
properties: false
}
mangle_props = {
ignore_quoted: true,
reserved: []
builtins: true,
keep_quoted: true
}
beautify = {
beautify: false,
@@ -234,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: []
}

View File

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

View File

@@ -41,22 +41,20 @@ reduce_vars: {
var A = 1;
(function() {
console.log(-3);
console.log(-4);
console.log(A - 5);
})();
(function f1() {
var a = 2;
console.log(-3);
console.log(a - 5);
eval("console.log(a);");
})();
(function f2(eval) {
var a = 2;
console.log(-3);
console.log(a - 5);
eval("console.log(a);");
})(eval);
(function() {
return "yes";
})();
console.log(2);
"yes";
console.log(A + 1);
}
expect_stdout: true
}
@@ -66,7 +64,7 @@ modified: {
conditionals : true,
evaluate : true,
reduce_vars : true,
unused : true
unused : true,
}
input: {
function f0() {
@@ -136,12 +134,11 @@ modified: {
}
function f2() {
var b = 2;
b = 3;
console.log(1 + b);
console.log(b + 3);
3;
console.log(4);
console.log(1 + b + 3);
console.log(6);
console.log(4);
console.log(7);
}
function f3() {
@@ -300,7 +297,7 @@ unsafe_evaluate_array: {
}
}
unsafe_evaluate_equality: {
unsafe_evaluate_equality_1: {
options = {
evaluate : true,
reduce_vars : true,
@@ -308,47 +305,62 @@ unsafe_evaluate_equality: {
unused : true
}
input: {
function f0(){
function f0() {
var a = {};
console.log(a === a);
return a === a;
}
function f1(){
function f1() {
var a = [];
console.log(a === a);
return a === a;
}
console.log(f0(), f1());
}
expect: {
function f0() {
return true;
}
function f1() {
return true;
}
console.log(f0(), f1());
}
expect_stdout: true
}
function f2(){
unsafe_evaluate_equality_2: {
options = {
collapse_vars: true,
evaluate : true,
passes : 2,
reduce_vars : true,
unsafe : true,
unused : true
}
input: {
function f2() {
var a = {a:1, b:2};
var b = a;
var c = a;
console.log(b === c);
return b === c;
}
function f3(){
function f3() {
var a = [1, 2, 3];
var b = a;
var c = a;
console.log(b === c);
return b === c;
}
console.log(f2(), f3());
}
expect: {
function f0(){
console.log(true);
function f2() {
return true;
}
function f1(){
console.log(true);
}
function f2(){
console.log(true);
}
function f3(){
console.log(true);
function f3() {
return true;
}
console.log(f2(), f3());
}
expect_stdout: true
}
passes: {
@@ -375,12 +387,11 @@ passes: {
}
expect: {
function f() {
var b = 2;
b = 3;
console.log(1 + b);
console.log(b + 3);
3;
console.log(4);
console.log(1 + b + 3);
console.log(6);
console.log(4);
console.log(7);
}
}
}
@@ -573,7 +584,7 @@ inner_var_label: {
}
}
inner_var_for: {
inner_var_for_1: {
options = {
evaluate: true,
reduce_vars: true,
@@ -602,6 +613,29 @@ inner_var_for: {
}
}
inner_var_for_2: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = 1;
for (var b = 1; --b;) var a = 2;
console.log(a);
}();
}
expect: {
!function() {
a = 1;
for (var b = 1; --b;) var a = 2;
console.log(a);
}();
}
expect_stdout: "1"
}
inner_var_for_in_1: {
options = {
evaluate: true,
@@ -1399,6 +1433,8 @@ issue_1670_1: {
evaluate: true,
dead_code: true,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1429,6 +1465,8 @@ issue_1670_2: {
dead_code: true,
passes: 2,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1458,6 +1496,8 @@ issue_1670_3: {
evaluate: true,
dead_code: true,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1488,6 +1528,8 @@ issue_1670_4: {
dead_code: true,
passes: 2,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1516,6 +1558,8 @@ issue_1670_5: {
evaluate: true,
keep_fargs: false,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1544,6 +1588,8 @@ issue_1670_6: {
evaluate: true,
keep_fargs: false,
reduce_vars: true,
side_effects: true,
switches: true,
unused: true,
}
input: {
@@ -1627,7 +1673,7 @@ redefine_arguments_1: {
return typeof arguments;
}
function g() {
return"number";
return "number";
}
function h(x) {
var arguments = x;
@@ -1666,9 +1712,7 @@ redefine_arguments_2: {
console.log(function() {
var arguments;
return typeof arguments;
}(), function() {
return"number";
}(), function(x) {
}(), "number", function(x) {
var arguments = x;
return typeof arguments;
}());
@@ -1705,7 +1749,10 @@ redefine_arguments_3: {
console.log(function() {
var arguments;
return typeof arguments;
}(), "number", "undefined");
}(), "number", function(x) {
var arguments = x;
return typeof arguments;
}());
}
expect_stdout: "object number undefined"
}
@@ -1777,9 +1824,7 @@ redefine_farg_2: {
console.log(function(a) {
var a;
return typeof a;
}([]), function() {
return "number";
}(),function(a, b) {
}([]), "number",function(a, b) {
var a = b;
return typeof a;
}([]));
@@ -1816,10 +1861,7 @@ redefine_farg_3: {
console.log(function(a) {
var a;
return typeof a;
}([]), "number", function(a) {
var a = void 0;
return typeof a;
}([]));
}([]), "number", "undefined");
}
expect_stdout: "object number undefined"
}
@@ -1854,3 +1896,644 @@ delay_def: {
}
expect_stdout: true
}
booleans: {
options = {
booleans: true,
evaluate: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
if (a != 0);
switch (a) {
case 0:
return "FAIL";
case false:
return "PASS";
}
}(false));
}
expect: {
console.log(function(a) {
if (!1);
switch (!1) {
case 0:
return "FAIL";
case !1:
return "PASS";
}
}(!1));
}
expect_stdout: "PASS"
}
side_effects_assign: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var a = typeof void (a && a.in == 1, 0);
console.log(a);
}
expect: {
var a = typeof void (a && a.in);
console.log(a);
}
expect_stdout: "undefined"
}
pure_getters_1: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
try {
var a = (a.b, 2);
} catch (e) {}
console.log(a);
}
expect: {
try {
var a = (a.b, 2);
} catch (e) {}
console.log(a);
}
expect_stdout: "undefined"
}
pure_getters_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
var a = a && a.b;
}
expect: {
var a = a && a.b;
}
}
pure_getters_3: {
options = {
pure_getters: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
var a = a && a.b;
}
expect: {
}
}
catch_var: {
options = {
booleans: true,
evaluate: true,
reduce_vars: true,
}
input: {
try {
throw {};
} catch (e) {
var e;
console.log(!!e);
}
}
expect: {
try {
throw {};
} catch (e) {
var e;
console.log(!!e);
}
}
expect_stdout: "true"
}
var_assign_1: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
!function() {
var a;
a = 2;
console.log(a);
}();
}
expect: {
!function() {
console.log(2);
}();
}
expect_stdout: "2"
}
var_assign_2: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
!function() {
var a;
if (a = 2) console.log(a);
}();
}
expect: {
!function() {
if (2) console.log(2);
}();
}
expect_stdout: "2"
}
var_assign_3: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
!function() {
var a;
while (a = 2);
console.log(a);
}();
}
expect: {
!function() {
var a;
while (a = 2);
console.log(a);
}();
}
}
var_assign_4: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
!function a() {
a = 2;
console.log(a);
}();
}
expect: {
!function a() {
a = 2,
console.log(a);
}();
}
}
var_assign_5: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
!function() {
var a;
!function(b) {
a = 2;
console.log(a, b);
}(a);
}();
}
expect: {
!function() {
var a;
!function(b) {
a = 2,
console.log(a, b);
}(a);
}();
}
expect_stdout: "2 undefined"
}
var_assign_6: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = function(){}(a = 1);
console.log(a);
}();
}
expect: {
!function() {
var a = function(){}(a = 1);
console.log(a);
}();
}
expect_stdout: "undefined"
}
immutable: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = "test";
console.log(a.indexOf("e"));
}();
}
expect: {
!function() {
console.log("test".indexOf("e"));
}();
}
expect_stdout: "1"
}
issue_1814_1: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
const a = 42;
!function() {
var b = a;
!function(a) {
console.log(a++, b);
}(0);
}();
}
expect: {
const a = 42;
!function() {
!function(a) {
console.log(a++, 42);
}(0);
}();
}
expect_stdout: "0 42"
}
issue_1814_2: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
const a = "32";
!function() {
var b = a + 1;
!function(a) {
console.log(a++, b);
}(0);
}();
}
expect: {
const a = "32";
!function() {
!function(a) {
console.log(a++, "321");
}(0);
}();
}
expect_stdout: "0 '321'"
}
try_abort: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
try {
var a = 1;
throw "";
var b = 2;
} catch (e) {
}
console.log(a, b);
}();
}
expect: {
!function() {
try {
var a = 1;
throw "";
var b = 2;
} catch (e) {
}
console.log(a, b);
}();
}
expect_stdout: "1 undefined"
}
boolean_binary_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a;
void 0 && (a = 1);
console.log(a);
}();
}
expect: {
!function() {
var a;
void 0;
console.log(a);
}();
}
expect_stdout: "undefined"
}
cond_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a;
void 0 ? (a = 1) : 0;
console.log(a);
}();
}
expect: {
!function() {
var a;
void 0 ? (a = 1) : 0;
console.log(a);
}();
}
expect_stdout: "undefined"
}
iife_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = 1, b = 0;
!function() {
b++;
return;
a = 2;
}();
console.log(a);
}();
}
expect: {
!function() {
var a = 1, b = 0;
!function() {
b++;
return;
a = 2;
}();
console.log(a);
}();
}
expect_stdout: "1"
}
issue_1850_1: {
options = {
reduce_vars: true,
toplevel: false,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_2: {
options = {
reduce_vars: true,
toplevel: "funcs",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}
issue_1850_3: {
options = {
reduce_vars: true,
toplevel: "vars",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_4: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}
issue_1865: {
options = {
evaluate: true,
reduce_vars: true,
unsafe: true,
}
input: {
function f(some) {
some.thing = false;
}
console.log(function() {
var some = { thing: true };
f(some);
return some.thing;
}());
}
expect: {
function f(some) {
some.thing = false;
}
console.log(function() {
var some = { thing: true };
f(some);
return some.thing;
}());
}
expect_stdout: true
}
issue_1922_1: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
arguments[0] = 2;
return a;
}(1));
}
expect: {
console.log(function(a) {
arguments[0] = 2;
return a;
}(1));
}
expect_stdout: "2"
}
issue_1922_2: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
var a;
eval("a = 1");
return a;
}(1));
}
expect: {
console.log(function() {
var a;
eval("a = 1");
return a;
}(1));
}
expect_stdout: "1"
}
accessor: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
console.log({
get a() {
a = 2;
return a;
},
b: 1
}.b, a);
}
expect: {
var a = 1;
console.log({
get a() {
a = 2;
return a;
},
b: 1
}.b, a);
}
expect_stdout: "1 1"
}

View File

@@ -1,9 +1,9 @@
do_screw: {
options = {
screw_ie8: true,
ie8: false,
}
beautify = {
screw_ie8: true,
ie8: false,
ascii_only: true,
}
input: {
@@ -14,10 +14,10 @@ do_screw: {
dont_screw: {
options = {
screw_ie8: false,
ie8: true,
}
beautify = {
screw_ie8: false,
ie8: true,
ascii_only: true,
}
input: {
@@ -28,7 +28,7 @@ dont_screw: {
do_screw_constants: {
options = {
screw_ie8: true,
ie8: false,
}
input: {
f(undefined, Infinity);
@@ -38,7 +38,7 @@ do_screw_constants: {
dont_screw_constants: {
options = {
screw_ie8: false,
ie8: true,
}
input: {
f(undefined, Infinity);
@@ -47,9 +47,15 @@ dont_screw_constants: {
}
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){
@@ -75,9 +81,15 @@ do_screw_try_catch: {
}
dont_screw_try_catch: {
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){
@@ -103,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 {
@@ -132,9 +150,15 @@ do_screw_try_catch_undefined: {
}
dont_screw_try_catch_undefined: {
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 {
@@ -164,11 +188,11 @@ reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
screw_ie8: false,
ie8: true,
unused: true,
}
mangle = {
screw_ie8: false,
ie8: true,
}
input: {
function f() {
@@ -196,10 +220,10 @@ reduce_vars: {
issue_1586_1: {
options = {
screw_ie8: false,
ie8: true,
}
mangle = {
screw_ie8: false,
ie8: true,
}
input: {
function f() {
@@ -215,10 +239,10 @@ issue_1586_1: {
issue_1586_2: {
options = {
screw_ie8: true,
ie8: false,
}
mangle = {
screw_ie8: true,
ie8: false,
}
input: {
function f() {

View File

@@ -440,3 +440,297 @@ func_def_5: {
}
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
}

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(/[\\\\/]/)}"
}

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();
@@ -263,6 +317,8 @@ issue_1663: {
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
var a = 100, b = 10;
@@ -294,6 +350,7 @@ issue_1663: {
drop_case: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
@@ -312,6 +369,7 @@ drop_case: {
keep_case: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
@@ -332,6 +390,7 @@ issue_376: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
switch (true) {
@@ -354,6 +413,7 @@ issue_376: {
issue_441_1: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
@@ -381,6 +441,7 @@ issue_441_1: {
issue_441_2: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (foo) {
@@ -414,6 +475,8 @@ issue_1674: {
options = {
dead_code: true,
evaluate: true,
side_effects: true,
switches: true,
}
input: {
switch (0) {
@@ -435,6 +498,7 @@ issue_1679: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
var a = 100, b = 10;
@@ -482,6 +546,7 @@ issue_1680_1: {
options = {
dead_code: true,
evaluate: true,
switches: true,
}
input: {
function f(x) {
@@ -522,6 +587,7 @@ issue_1680_1: {
issue_1680_2: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = 100, b = 10;
@@ -557,6 +623,7 @@ issue_1680_2: {
issue_1690_1: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (console.log("PASS")) {}
@@ -570,6 +637,7 @@ issue_1690_1: {
issue_1690_2: {
options = {
dead_code: false,
switches: true,
}
input: {
switch (console.log("PASS")) {}
@@ -585,6 +653,7 @@ if_switch_typeof: {
conditionals: true,
dead_code: true,
side_effects: true,
switches: true,
}
input: {
if (a) switch(typeof b) {}
@@ -597,6 +666,7 @@ if_switch_typeof: {
issue_1698: {
options = {
side_effects: true,
switches: true,
}
input: {
var a = 1;
@@ -618,6 +688,7 @@ issue_1698: {
issue_1705_1: {
options = {
dead_code: true,
switches: true,
}
input: {
var a = 0;
@@ -646,6 +717,7 @@ issue_1705_2: {
reduce_vars: true,
sequences: true,
side_effects: true,
switches: true,
toplevel: true,
unused: true,
}
@@ -666,6 +738,7 @@ issue_1705_2: {
issue_1705_3: {
options = {
dead_code: true,
switches: true,
}
input: {
switch (a) {
@@ -721,3 +794,25 @@ beautify: {
"}",
]
}
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"
}

View File

@@ -45,7 +45,7 @@ template_strings_without_ascii_only: {
bar
ↂωↂ`
}
expect_exact: "var foo=`foo\n bar\n ↂωↂ`;"
expect_exact: "var foo=`foo\\n bar\\n ↂωↂ`;"
}
template_string_with_constant_expression: {
@@ -351,7 +351,8 @@ template_starting_with_newline: {
return `
this is a template string!`;
};
} expect_exact: "function foo(e){return`\nthis is a template string!`}"
}
expect_exact: "function foo(e){return`\\nthis is a template string!`}"
}
template_with_newline: {
@@ -363,7 +364,8 @@ template_with_newline: {
return `yep,
this is a template string!`;
};
} expect_exact: "function foo(e){return`yep,\nthis is a template string!`}"
}
expect_exact: "function foo(e){return`yep,\\nthis is a template string!`}"
}
template_ending_with_newline: {
@@ -375,5 +377,26 @@ template_ending_with_newline: {
return `this is a template string!
`;
};
} expect_exact: "function foo(e){return`this is a template string!\n`}"
}
expect_exact: "function foo(e){return`this is a template string!\\n`}"
}
issue_1856: {
beautify = {
ascii_only: false,
}
input: {
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
}
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
}
issue_1856_ascii_only: {
beautify = {
ascii_only: true,
}
input: {
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
}
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
}

View File

@@ -190,3 +190,12 @@ yield_sub: {
}
expect_exact: 'function*foo(){yield x["foo"];(yield x)["foo"];yield(yield obj.foo())["bar"]()}'
}
yield_as_ES5_property: {
input: {
"use strict";
console.log({yield: 42}.yield);
}
expect_exact: '"use strict";console.log({yield:42}.yield);'
expect_stdout: "42"
}

13
test/exports.js Normal file
View File

@@ -0,0 +1,13 @@
exports["Compressor"] = Compressor;
exports["JS_Parse_Error"] = JS_Parse_Error;
exports["OutputStream"] = OutputStream;
exports["SourceMap"] = SourceMap;
exports["TreeWalker"] = TreeWalker;
exports["base54"] = base54;
exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify;
exports["parse"] = parse;
exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier;

View File

@@ -0,0 +1 @@
++null

View File

@@ -0,0 +1,8 @@
function f() {
const a;
}
function g() {
"use strict";
const a;
}

View File

@@ -0,0 +1,14 @@
function f(x) {
delete 42;
delete (0, x);
delete null;
delete x;
}
function g(x) {
"use strict";
delete 42;
delete (0, x);
delete null;
delete x;
}

View File

@@ -0,0 +1 @@
a.=

View File

@@ -0,0 +1 @@
%.a;

View File

@@ -0,0 +1 @@
a./();

View File

@@ -0,0 +1 @@
if (0) else 1;

View File

@@ -0,0 +1,6 @@
function f(arguments) {
}
function g(arguments) {
"use strict";
}

View File

@@ -0,0 +1,6 @@
function arguments() {
}
function eval() {
"use strict";
}

View File

@@ -0,0 +1,6 @@
!function eval() {
}();
!function arguments() {
"use strict";
}();

View File

@@ -0,0 +1 @@
console.log({%: 1});

View File

@@ -0,0 +1 @@
return 42;

View File

@@ -0,0 +1,8 @@
function f() {
try {} catch (eval) {}
}
function g() {
"use strict";
try {} catch (eval) {}
}

View File

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

View File

@@ -0,0 +1,5 @@
function test(callback) {
'aaaaaaaaaaaaaaaa';
callback(err, data);
callback(err, data);
}

View File

@@ -0,0 +1,5 @@
function test(a){
"aaaaaaaaaaaaaaaa"
;a(err,data),a(err,data)
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQyxJQUFLQyJ9

View File

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

View File

@@ -12,9 +12,9 @@ if (typeof phantom == "undefined") {
});
var args = process.argv.slice(2);
if (!args.length) {
args.push("-mc", "warnings=false");
args.push("-mc");
}
args.push("--stats");
args.push("--timings");
var child_process = require("child_process");
try {
require("phantomjs-prebuilt");

View File

@@ -1,4 +1,4 @@
var UglifyJS = require('../../');
var UglifyJS = require("../node");
var assert = require("assert");
describe("Accessor tokens", function() {

View File

@@ -1,4 +1,4 @@
var UglifyJS = require('../../');
var UglifyJS = require("../node");
var assert = require("assert");
describe("arguments", function() {

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Arrow functions", function() {
it("Should not accept spread tokens on non-last parameters or without arguments parentheses", function() {
@@ -10,7 +10,7 @@ describe("Arrow functions", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -28,7 +28,7 @@ describe("Arrow functions", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -49,7 +49,7 @@ describe("Arrow functions", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -68,7 +68,7 @@ describe("Arrow functions", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -385,7 +385,6 @@ describe("Arrow functions", function() {
it("Should handle arrow function with bind", function() {
function minify(code) {
return uglify.minify(code, {
fromString: true,
mangle: false
}).code;
}

View File

@@ -7,7 +7,7 @@ describe("builtins", function() {
" return [Object,Array,Function,Number,String,Boolean,Error,Math,Date,RegExp,Symbol,Map,Promise,Proxy,Reflect,Set,WeakMap,WeakSet,Float32Array,something];\n" +
"};";
var result = UglifyJS.minify(test, {fromString: true, parse: {bare_returns: true}}).code;
var result = UglifyJS.minify(test, {parse: {bare_returns: true}}).code;
assert.strictEqual(result.indexOf("something"), -1);

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Class", function() {
it("Should not accept spread on non-last parameters in methods", function() {
@@ -11,7 +11,7 @@ describe("Class", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {

View File

@@ -2,6 +2,10 @@ var assert = require("assert");
var exec = require("child_process").exec;
var readFileSync = require("fs").readFileSync;
function read(path) {
return readFileSync(path, "utf8");
}
describe("bin/uglifyjs", function () {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("should produce a functional build when using --self", function (done) {
@@ -15,12 +19,14 @@ describe("bin/uglifyjs", function () {
eval(stdout);
assert.strictEqual(typeof WrappedUglifyJS, 'object');
assert.strictEqual(true, WrappedUglifyJS.parse('foo;') instanceof WrappedUglifyJS.AST_Node);
var result = WrappedUglifyJS.minify("foo([true,,2+3]);");
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, "foo([!0,,5]);");
done();
});
});
it("Should be able to filter comments correctly with `--comment all`", function (done) {
it("Should be able to filter comments correctly with `--comments all`", function (done) {
var command = uglifyjscmd + ' test/input/comments/filter.js --comments all';
exec(command, function (err, stdout) {
@@ -50,18 +56,18 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should append source map to output when using --source-map-inline", function (done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js --source-map-inline';
it("Should append source map to output when using --source-map url=inline", function (done) {
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map url=inline";
exec(command, function (err, stdout) {
if (err) throw err;
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
done();
});
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n");
done();
});
});
it("should not append source map to output when not using --source-map-inline", function (done) {
it("should not append source map to output when not using --source-map url=inline", function (done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
exec(command, function (err, stdout) {
@@ -72,130 +78,134 @@ describe("bin/uglifyjs", function () {
});
});
it("Should work with --keep-fnames (mangle only)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --keep-fnames (mangle & compress)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
done();
});
});
it("Should work with keep_fnames under mangler options", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --define (simple)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(5);\n");
done();
});
});
it("Should work with --define (nested)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(3,5);\n");
done();
});
});
it("Should work with --define (AST_Node)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "stdout.println(D);\n");
done();
});
});
it("Should work with `--beautify`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8"));
done();
});
});
it("Should work with `--beautify bracketize`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8"));
done();
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline';
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, readFileSync("test/input/issue-520/output.js", "utf8"));
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --keep-fnames (mangle & compress)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
done();
});
});
it("Should work with keep_fnames under mangler options", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --define (simple)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(5);\n");
done();
});
});
it("Should work with --define (nested)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(3,5);\n");
done();
});
});
it("Should work with --define (AST_Node)", function (done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "stdout.println(D);\n");
done();
});
});
it("Should work with `--beautify`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
done();
});
});
it("Should work with `--beautify bracketize`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/bracketize.js"));
done();
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline";
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-520/output.js"));
done();
});
});
it("Should warn for missing inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js --in-source-map inline';
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map content=inline,url=inline";
exec(command, function (err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n");
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=",
"",
].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n");
done();
});
});
it("Should fail with multiple input and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js test/input/issue-520/output.js --in-source-map inline --source-map-inline';
var command = uglifyjscmd + " test/input/issue-520/input.js test/input/issue-520/output.js --source-map content=inline,url=inline";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with singular input\n");
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
done();
});
});
it("Should fail with acorn and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --acorn';
var command = uglifyjscmd + " test/input/issue-520/input.js --source-map content=inline,url=inline -p acorn";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n");
assert.strictEqual(stderr, "ERROR: inline source map only works with built-in parser\n");
done();
});
});
it("Should fail with SpiderMonkey and inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --spidermonkey';
var command = uglifyjscmd + " test/input/issue-520/input.js --source-map content=inline,url=inline -p spidermonkey";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n");
assert.strictEqual(stderr, "ERROR: inline source map only works with built-in parser\n");
done();
});
});
@@ -208,7 +218,7 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12");
assert.strictEqual(lines[1], "function f(a{}");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token punc «{», expected punc «,»");
assert.strictEqual(lines[3], "ERROR: Unexpected token punc «{», expected punc «,»");
done();
});
});
@@ -221,7 +231,7 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(lines[0], "Parse error at test/input/invalid/tab.js:1,12");
assert.strictEqual(lines[1], "\t\tfoo(\txyz, 0abc);");
assert.strictEqual(lines[2], "\t\t \t ^");
assert.strictEqual(lines[3], "SyntaxError: Invalid syntax: 0abc");
assert.strictEqual(lines[3], "ERROR: Invalid syntax: 0abc");
done();
});
});
@@ -234,7 +244,7 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0");
assert.strictEqual(lines[1], "foo, bar(");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof (undefined)");
done();
});
});
@@ -247,63 +257,308 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0");
assert.strictEqual(lines[1], "for (var i = 0; i < 1; i++) ");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof (undefined)");
done();
});
});
it("Should support hyphen as shorthand", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should throw syntax error (5--)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_1.js:1,18",
"console.log(1 || 5--);",
" ^",
"SyntaxError: Invalid use of -- operator"
].join("\n"));
done();
});
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_1.js:1,18",
"console.log(1 || 5--);",
" ^",
"ERROR: Invalid use of -- operator"
].join("\n"));
done();
});
});
it("Should throw syntax error (Math.random() /= 2)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_2.js:1,32",
"console.log(2 || (Math.random() /= 2));",
" ^",
"SyntaxError: Invalid assignment"
].join("\n"));
done();
});
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_2.js:1,32",
"console.log(2 || (Math.random() /= 2));",
" ^",
"ERROR: Invalid assignment"
].join("\n"));
done();
});
});
it("Should throw syntax error (++this)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_3.js:1,18",
"console.log(3 || ++this);",
" ^",
"SyntaxError: Invalid use of ++ operator"
].join("\n"));
done();
});
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_3.js:1,17",
"console.log(3 || ++this);",
" ^",
"ERROR: Invalid use of ++ operator"
].join("\n"));
done();
});
});
it("Should throw syntax error (++null)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_4.js:1,0",
"++null",
"^",
"ERROR: Invalid use of ++ operator"
].join("\n"));
done();
});
});
it("Should throw syntax error (a.=)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/dot_1.js:1,2",
"a.=",
" ^",
"ERROR: Unexpected token: operator (=)"
].join("\n"));
done();
});
});
it("Should throw syntax error (%.a)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/dot_2.js:1,0",
"%.a;",
"^",
"ERROR: Unexpected token: operator (%)"
].join("\n"));
done();
});
});
it("Should throw syntax error (a./();)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/dot_3.js:1,2",
"a./();",
" ^",
"ERROR: Unexpected token: operator (/)"
].join("\n"));
done();
});
});
it("Should throw syntax error ({%: 1})", function(done) {
var command = uglifyjscmd + ' test/input/invalid/object.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/object.js:1,13",
"console.log({%: 1});",
" ^",
"ERROR: Unexpected token: operator (%)"
].join("\n"));
done();
});
});
it("Should throw syntax error (const a)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/const.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/const.js:7,11",
" const a;",
" ^",
"ERROR: Missing initializer in const declaration"
].join("\n"));
done();
});
});
it("Should throw syntax error (delete x)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/delete.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/delete.js:13,11",
" delete x;",
" ^",
"ERROR: Calling delete on expression not allowed in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (function g(arguments))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/function_1.js:4,11",
"function g(arguments) {",
" ^",
"ERROR: Unexpected arguments in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (function eval())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/function_2.js:4,9",
"function eval() {",
" ^",
"ERROR: Unexpected eval in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (iife arguments())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/function_3.js:4,10",
"!function arguments() {",
" ^",
"ERROR: Unexpected arguments in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (catch(eval))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/try.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/try.js:7,18",
" try {} catch (eval) {}",
" ^",
"ERROR: Unexpected eval identifier as parameter inside strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (var eval)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/var.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/var.js:7,8",
" var eval;",
" ^",
"ERROR: Unexpected eval in strict mode"
].join("\n"));
done();
});
});
it("Should throw syntax error (else)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/else.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/else.js:1,7",
"if (0) else 1;",
" ^",
"ERROR: Unexpected token: keyword (else)"
].join("\n"));
done();
});
});
it("Should throw syntax error (return)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/return.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/return.js:1,0",
"return 42;",
"^",
"ERROR: 'return' outside of function"
].join("\n"));
done();
});
});
it("Should handle literal string as source map input", function(done) {
var command = [
uglifyjscmd,
"test/input/issue-1236/simple.js",
"--source-map",
'content="' + read_map() + '",url=inline'
].join(" ");
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, [
'"use strict";var foo=function foo(x){return"foo "+x};console.log(foo("bar"));',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiYUFBQSxJQUFJQSxJQUFNLFNBQU5BLElBQU1DLEdBQUEsTUFBSyxPQUFTQSxHQUN4QkMsUUFBUUMsSUFBSUgsSUFBSSJ9",
""
].join("\n"));
done();
});
function read_map() {
var map = JSON.parse(read("./test/input/issue-1236/simple.js.map"));
delete map.sourcesContent;
return JSON.stringify(map).replace(/"/g, '\\"');
}
});
it("Should dump AST as JSON", function(done) {
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
exec(command, function (err, stdout) {
if (err) throw err;
var ast = JSON.parse(stdout);
assert.strictEqual(ast._class, "AST_Toplevel");
assert.ok(Array.isArray(ast.body));
done();
});
});
it("Should print supported options on invalid option syntax", function(done) {
var command = uglifyjscmd + " test/input/comments/filter.js -b ascii-only";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.ok(/^Supported options:\n\{[^}]+}\nERROR: `ascii-only` is not a supported option/.test(stderr), stderr);
done();
});
});
});

View File

@@ -1,4 +1,4 @@
var UglifyJS = require('../../');
var UglifyJS = require("../node");
var assert = require("assert");
describe("comment filters", function() {
@@ -75,9 +75,15 @@ describe("comment filters", function() {
it("Should handle shebang and preamble correctly", function() {
var code = UglifyJS.minify("#!/usr/bin/node\nvar x = 10;", {
fromString: true,
output: { preamble: "/* Build */" }
}).code;
assert.strictEqual(code, "#!/usr/bin/node\n/* Build */\nvar x=10;");
})
});
it("Should handle preamble without shebang correctly", function() {
var code = UglifyJS.minify("var x = 10;", {
output: { preamble: "/* Build */" }
}).code;
assert.strictEqual(code, "/* Build */\nvar x=10;");
});
});

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Comment", function() {
it("Should recognize eol of single line comments", function() {
@@ -20,7 +20,7 @@ describe("Comment", function() {
for (var i = 0; i < tests.length; i++) {
assert.throws(function() {
uglify.parse(tests[i], {fromString: true})
uglify.parse(tests[i]);
}, fail, tests[i]);
}
});
@@ -44,7 +44,7 @@ describe("Comment", function() {
for (var i = 0; i < tests.length; i++) {
assert.throws(function() {
uglify.parse(tests[i], {fromString: true});
uglify.parse(tests[i]);
}, fail, tests[i]);
}
});

View File

@@ -6,9 +6,7 @@ describe("comment before constant", function() {
it("Should test comment before constant is retained and output after mangle.", function() {
var result = Uglify.minify(js, {
fromString: true,
compress: { collapse_vars: false, reduce_vars: false },
mangle: {},
output: { comments: true },
});
assert.strictEqual(result.code, 'function f(){/*c1*/var/*c2*/n=/*c3*/!1;return n}');
@@ -16,12 +14,9 @@ describe("comment before constant", function() {
it("Should test code works when comments disabled.", function() {
var result = Uglify.minify(js, {
fromString: true,
compress: { collapse_vars: false, reduce_vars: false },
mangle: {},
output: { comments: false },
});
assert.strictEqual(result.code, 'function f(){var n=!1;return n}');
});
});

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Destructuring", function() {
it("Should generate similar trees for destructuring in left hand side expressions, definitions, functions and arrow functions", function() {

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Directives", function() {
it ("Should allow tokenizer to store directives state", function() {
@@ -207,7 +207,7 @@ describe("Directives", function() {
assert.strictEqual(
uglify.minify(
'"use strict";\'use strict\';"use strict";"use strict";;\'use strict\';console.log(\'use strict\');',
{fromString: true, output: {beautify: true, quote_style: 3}, compress: false}
{output: {beautify: true, quote_style: 3}, compress: false}
).code,
'"use strict";\n\n\'use strict\';\n\n"use strict";\n\n"use strict";\n\n;\'use strict\';\n\nconsole.log(\'use strict\');'
);
@@ -235,7 +235,7 @@ describe("Directives", function() {
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(
uglify.minify(tests[i][0], {fromString: true, quote_style: 3, compress: false, mangle: false}).code,
uglify.minify(tests[i][0], {compress: false, mangle: false}).code,
tests[i][1],
tests[i][0]
);
@@ -244,7 +244,7 @@ describe("Directives", function() {
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
var code = uglify.minify('"use strict";"use\\x20strict";',
{fromString: true, output: {semicolons: false}, compress: false}
{output: {semicolons: false}, compress: false}
).code;
assert.strictEqual(code, '"use strict";;"use strict"\n');
});
@@ -350,7 +350,7 @@ describe("Directives", function() {
];
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(
uglify.minify(tests[i][0], {fromString: true, output:{quote_style: tests[i][1]}, compress: false}).code,
uglify.minify(tests[i][0], {output:{quote_style: tests[i][1]}, compress: false}).code,
tests[i][2],
tests[i][0] + " using mode " + tests[i][1]
);
@@ -361,18 +361,28 @@ describe("Directives", function() {
var tests = [
[
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
'"use strict";"use foo";doSomething("foo");'
'"use strict";"use foo";doSomething("foo");',
'function f(){ "use strict" }',
'function f(){ "use asm" }',
'function f(){ "use nondirective" }',
'function f(){ ;"use strict" }',
'function f(){ "use \n"; }',
],
[
// Nothing gets optimised in the compressor because "use asm" is the first statement
'"use asm";"use\\x20strict";1+1;',
'"use asm";;"use strict";1+1;' // Yet, the parser noticed that "use strict" wasn't a directive
'"use asm";;"use strict";1+1;', // Yet, the parser noticed that "use strict" wasn't a directive
'function f(){"use strict"}',
'function f(){"use asm"}',
'function f(){"use nondirective"}',
'function f(){}',
'function f(){}',
]
];
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(
uglify.minify(tests[i][0], {fromString: true, compress: {collapse_vars: true, side_effects: true}}).code,
uglify.minify(tests[i][0]).code,
tests[i][1],
tests[i][0]
);

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("EOF", function() {
it("Should test code for at least throwing syntax error when incomplete", function() {

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Export", function() {
it ("Should parse export directives", function() {
@@ -13,7 +13,7 @@ describe("Export", function() {
];
var test = function(code) {
return uglify.parse(code, {fromString: true});
return uglify.parse(code);
};
var extractNames = function(symbols) {

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Expression", function() {
it("Should not allow the first exponentiation operator to be prefixed with an unary operator", function() {

View File

@@ -1,5 +1,5 @@
var assert = require("assert");
var uglify = require("../../");
var uglify = require("../node");
describe("Function", function() {
it ("Should parse binding patterns correctly", function() {
@@ -172,7 +172,7 @@ describe("Function", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -191,7 +191,7 @@ describe("Function", function() {
];
var test = function(code) {
return function() {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function(e) {
@@ -209,7 +209,7 @@ describe("Function", function() {
];
var test = function(code) {
return function () {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function (e) {
@@ -238,7 +238,7 @@ describe("Function", function() {
];
var test = function(code) {
return function () {
uglify.parse(code, {fromString: true});
uglify.parse(code);
}
}
var error = function (e) {

View File

@@ -1,4 +1,4 @@
var UglifyJS = require('../../');
var UglifyJS = require("../node");
var assert = require("assert");
describe("Getters and setters", function() {

View File

@@ -1,58 +1,80 @@
var Uglify = require('../../');
var assert = require("assert");
var exec = require("child_process").exec;
var path = require("path");
var readFileSync = require("fs").readFileSync;
describe("minify() with input file globs", function() {
it("minify() with one input file glob string.", function() {
var result = Uglify.minify("test/input/issue-1242/foo.*");
assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
});
it("minify() with an array of one input file glob.", function() {
var result = Uglify.minify([
"test/input/issue-1242/b*.es5",
]);
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}');
});
it("minify() with an array of multiple input file globs.", function() {
var result = Uglify.minify([
"test/input/issue-1242/???.es5",
"test/input/issue-1242/*.js",
], {
compress: { toplevel: true }
describe("bin/uglifyjs with input file globs", function() {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("bin/uglifyjs with one input file extension glob.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/foo.*" -cm';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);\n');
done();
});
assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);');
});
it("should throw with non-matching glob string", function() {
var glob = "test/input/issue-1242/blah.*";
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
assert.throws(function() {
Uglify.minify(glob);
}, "should throw file not found");
it("bin/uglifyjs with one input file name glob.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/b*.es5" -cm';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'function bar(n){return 3*n}function baz(n){return n/2}\n');
done();
});
});
it('"?" in glob string should not match "/"', function() {
var glob = "test/input?issue-1242/foo.*";
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
assert.throws(function() {
Uglify.minify(glob);
}, "should throw file not found");
it("bin/uglifyjs with multiple input file globs.", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);\n');
done();
});
});
it("should handle special characters in glob string", function() {
var result = Uglify.minify("test/input/issue-1632/^{*}[???](*)+$.??");
assert.strictEqual(result.code, "console.log(x);");
it("should throw with non-matching glob string", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1242/blah.*"';
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.ok(/^ERROR: ENOENT/.test(stderr));
done();
});
});
it("should handle array of glob strings - matching and otherwise", function() {
it('"?" in glob string should not match "/"', function(done) {
var command = uglifyjscmd + ' "test/input?issue-1242/foo.*"';
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.ok(/^ERROR: ENOENT/.test(stderr));
done();
});
});
it("should handle special characters in glob string", function(done) {
var command = uglifyjscmd + ' "test/input/issue-1632/^{*}[???](*)+$.??" -cm';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(x);\n");
done();
});
});
it("should handle array of glob strings - matching and otherwise", function(done) {
var dir = "test/input/issue-1242";
var matches = Uglify.simple_glob([
var command = uglifyjscmd + ' "' + [
path.join(dir, "b*.es5"),
path.join(dir, "z*.es5"),
path.join(dir, "*.js"),
]);
assert.strictEqual(matches.length, 4);
assert.strictEqual(matches[0], path.join(dir, "bar.es5"));
assert.strictEqual(matches[1], path.join(dir, "baz.es5"));
assert.strictEqual(matches[2], path.join(dir, "z*.es5"));
assert.strictEqual(matches[3], path.join(dir, "qux.js"));
path.join(dir, "*.js")
].join('" "') + '"';
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.ok(/^ERROR: ENOENT.*?z\*\.es5/.test(stderr));
done();
});
});
});

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