Compare commits

..

130 Commits

Author SHA1 Message Date
Alex Lam S.L
b84c99ef5c harmony-v3.2.0 2017-11-26 06:02:49 +08:00
alexlamsl
4f08c2f504 Merge branch 'master' into harmony-v3.2.0 2017-11-26 04:23:57 +08:00
Alex Lam S.L
b37a68c84f v3.2.0 2017-11-26 04:08:35 +08:00
Alex Lam S.L
c141ae6f8d fix argument/atom collision by properties (#2514)
fixes #2513
2017-11-25 22:52:46 +08:00
Alex Lam S.L
97c464dbf5 fix wording and formatting (#2512) 2017-11-25 19:07:46 +08:00
kzc
ba4894af18 document top level minify option keep_classnames (#2511) 2017-11-25 16:33:03 +08:00
Alex Lam S.L
f1e3ef5262 separate keep_classnames & keep_fnames (#2510)
fixes #2418
2017-11-25 16:31:52 +08:00
Alex Lam S.L
3b28b915eb extend escape analysis on constant expression properties (#2509)
fixes #2508
2017-11-24 14:07:39 +08:00
Alex Lam S.L
eb001dc1d9 fix argument/atom collision by collapse_vars (#2507)
fixes #2506
2017-11-24 07:26:22 +08:00
Alex Lam S.L
aa9bdf416e make AST_Lambda.contains_this() less magical (#2505) 2017-11-24 07:03:37 +08:00
Alex Lam S.L
bbf38dc9c0 fix reduce_vars on arrow functions with this (#2504)
fixes #2496
2017-11-24 06:21:49 +08:00
Alex Lam S.L
8987780db6 eliminate invalid state caching in collapse_vars (#2502)
fixes #2497
2017-11-24 04:12:37 +08:00
Alex Lam S.L
30cfea2e7a fix rename (#2501)
- suppress spurious `rename` from `commander`
- handle `AST_SymbolCatch` correctly
2017-11-24 03:05:43 +08:00
kzc
3d8341a7ab fix properties for array literal with spread (#2499)
fixes #2498
2017-11-24 02:04:26 +08:00
Alex Lam S.L
f4e2fb9864 expand symbol space to improve compression (#2460)
- give globally distinct names to distinct variables
- improve ability to compress cross-scoped
- introduce `options.rename` to `minify()`
- default `true` if both `compress` & `mangle`
2017-11-19 19:29:51 +08:00
Alex Lam S.L
567cb0e4e3 harmony-v3.1.10 2017-11-19 15:53:22 +08:00
Alex Lam S.L
b80062c490 enable hoist_props by default (#2492) 2017-11-19 14:56:23 +08:00
alexlamsl
227b58812d Merge branch 'master' into harmony-v3.1.10 2017-11-19 14:34:27 +08:00
kzc
f25bd13be6 fix keyword shorthand property output for ecma >= 6 (#2493)
fixes #2491
2017-11-19 13:53:42 +08:00
Alex Lam S.L
667fc4d08b v3.1.10 2017-11-18 23:56:33 +08:00
kzc
6142117cdd document the webkit output option (#2490)
- workaround for WebKit bugs
- PhantomJS users should enable this output option

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

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

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

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

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


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

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

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

View File

@@ -15,6 +15,8 @@
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
Issues without a reproducible test case will be closed.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.**

343
README.md
View File

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

View File

@@ -15,7 +15,7 @@ var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ];
var files = {};
var options = {
compress: false,
@@ -44,10 +44,12 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("--ecma <version>", "Specifiy ECMAScript release: 5, 6, 7 or 8.");
program.option("--ecma <version>", "Specify ECMAScript release: 5, 6, 7 or 8.");
program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-classnames", "Do not mangle/drop class names.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.")
@@ -66,11 +68,13 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
"compress",
"ie8",
"mangle",
"rename",
"sourceMap",
"toplevel",
"wrap"
].forEach(function(name) {
if (name in program) {
if (name == "rename" && program[name]) return;
options[name] = program[name];
}
});
@@ -95,6 +99,9 @@ if (program.define) {
options.compress.global_defs[expr] = program.define[expr];
}
}
if (program.keepClassnames) {
options.keep_classnames = true;
}
if (program.keepFnames) {
options.keep_fnames = true;
}

View File

@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value scope quote", {
var AST_Directive = DEFNODE("Directive", "value quote", {
$documentation: "Represents a directive, like \"use strict\";",
$propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character"
},
}, AST_Statement);
@@ -303,10 +302,9 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
@@ -391,15 +389,15 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda);
var AST_Function = DEFNODE("Function", null, {
var AST_Function = DEFNODE("Function", "inlined", {
$documentation: "A function expression"
}, AST_Lambda);
var AST_Arrow = DEFNODE("Arrow", null, {
var AST_Arrow = DEFNODE("Arrow", "inlined", {
$documentation: "An ES6 Arrow function ((a) => b)"
}, AST_Lambda);
var AST_Defun = DEFNODE("Defun", null, {
var AST_Defun = DEFNODE("Defun", "inlined", {
$documentation: "A function definition"
}, AST_Lambda);
@@ -450,10 +448,8 @@ var AST_TemplateString = DEFNODE("TemplateString", "segments", {
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.segments.forEach(function(seg, i){
if (i % 2 !== 0) {
seg._walk(visitor);
}
this.segments.forEach(function(seg){
seg._walk(visitor);
});
});
}
@@ -1044,7 +1040,7 @@ var AST_This = DEFNODE("This", null, {
var AST_Super = DEFNODE("Super", null, {
$documentation: "The `super` symbol",
}, AST_Symbol);
}, AST_This);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",

File diff suppressed because it is too large Load Diff

View File

@@ -51,11 +51,13 @@ function minify(files, options) {
compress: {},
ecma: undefined,
ie8: false,
keep_classnames: undefined,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
rename: undefined,
sourceMap: false,
timings: false,
toplevel: false,
@@ -65,8 +67,15 @@ function minify(files, options) {
var timings = options.timings && {
start: Date.now()
};
if (options.keep_classnames === undefined) {
options.keep_classnames = options.keep_fnames;
}
if (options.rename === undefined) {
options.rename = options.compress && options.mangle;
}
set_shorthand("ecma", options, [ "parse", "compress", "output" ]);
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_classnames", options, [ "compress", "mangle" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
@@ -141,11 +150,14 @@ function minify(files, options) {
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
}
if (timings) timings.scope1 = Date.now();
if (options.compress) toplevel.figure_out_scope(options.mangle);
if (timings) timings.rename = Date.now();
if (options.rename) {
toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle);
}
if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope2 = Date.now();
if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
@@ -203,9 +215,10 @@ function minify(files, options) {
if (timings) {
timings.end = Date.now();
result.timings = {
parse: 1e-3 * (timings.scope1 - timings.parse),
scope: 1e-3 * (timings.compress - timings.scope1 + timings.mangle - timings.scope2),
compress: 1e-3 * (timings.scope2 - timings.compress),
parse: 1e-3 * (timings.rename - timings.parse),
rename: 1e-3 * (timings.compress - timings.rename),
compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),

View File

@@ -262,7 +262,7 @@ function OutputStream(options) {
}
} : noop;
var requireSemicolonChars = makePredicate("( [ + * / - , .");
var requireSemicolonChars = makePredicate("( [ + * / - , . `");
function print(str) {
str = String(str);
@@ -506,13 +506,17 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator);
};
var use_asm = false;
var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen, prev_use_asm = use_asm;
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
use_asm = true;
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
}
function doit() {
self.add_comments(stream);
@@ -526,8 +530,8 @@ function OutputStream(options) {
doit();
}
stream.pop_node();
if (self instanceof AST_Scope) {
use_asm = prev_use_asm;
if (self === use_asm) {
use_asm = null;
}
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
@@ -1357,6 +1361,7 @@ function OutputStream(options) {
self.exported_value.print(output);
} else if (self.exported_definition) {
self.exported_definition.print(output);
if (self.exported_definition instanceof AST_Definitions) return;
}
if (self.module_name) {
output.space();
@@ -1619,7 +1624,8 @@ function OutputStream(options) {
if (allowShortHand &&
self.value instanceof AST_Symbol &&
is_identifier_string(self.key) &&
get_name(self.value) === self.key
get_name(self.value) === self.key &&
is_identifier(self.key)
) {
print_property_name(self.key, self.quote, output);
@@ -1681,9 +1687,6 @@ function OutputStream(options) {
DEFPRINT(AST_Symbol, function (self, output) {
self._do_print(output);
});
DEFPRINT(AST_SymbolDeclaration, function(self, output){
self._do_print(output);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output){
output.print("this");

View File

@@ -44,9 +44,9 @@
"use strict";
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof new return switch throw try typeof var let void while with import';
var KEYWORDS = 'break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with';
var KEYWORDS_ATOM = 'false null true';
var RESERVED_WORDS = 'enum implements interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
var RESERVED_WORDS = 'enum implements import interface package private protected public static super this ' + KEYWORDS_ATOM + " " + KEYWORDS;
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case yield await';
KEYWORDS = makePredicate(KEYWORDS);
@@ -1013,6 +1013,12 @@ function parse($TEXT, options) {
next();
return function_(AST_Defun, false, true);
}
if (S.token.value == "import" && !is_token(peek(), "punc", "(")) {
next();
var node = import_();
semicolon();
return node;
}
return is_token(peek(), "punc", ":")
? labeled_statement()
: simple_statement();
@@ -1149,15 +1155,11 @@ function parse($TEXT, options) {
body : statement()
});
case "import":
next();
var node = import_();
semicolon();
return node;
case "export":
next();
return export_();
if (!is_token(peek(), "punc", "(")) {
next();
return export_();
}
}
}
unexpected();
@@ -1320,6 +1322,9 @@ function parse($TEXT, options) {
if (in_statement && !name)
unexpected();
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
unexpected(prev());
var args = parameters();
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
return new ctor({
@@ -1875,7 +1880,8 @@ function parse($TEXT, options) {
: !no_in && kind === "const" && S.input.has_directive("use strict")
? croak("Missing initializer in const declaration") : null,
end : prev()
})
});
if (def.name.name == "import") croak("Unexpected token: import");
}
a.push(def);
if (!is("punc", ","))
@@ -1994,9 +2000,6 @@ function parse($TEXT, options) {
names: ex.properties.map(to_fun_args)
}), default_seen_above);
} else if (ex instanceof AST_ObjectKeyVal) {
if (ex.key instanceof AST_SymbolRef) {
ex.key = to_fun_args(ex.key, 0, [ex.key]);
}
ex.value = to_fun_args(ex.value, 0, [ex.key]);
return insert_default(ex, default_seen_above);
} else if (ex instanceof AST_Hole) {
@@ -2104,7 +2107,8 @@ function parse($TEXT, options) {
}));
while (S.token.end === false) {
next();
segments.push(expression());
handle_regexp();
segments.push(expression(true));
if (!is_token("template_substitution")) {
unexpected();
@@ -2562,7 +2566,7 @@ function parse($TEXT, options) {
unexpected(tmp);
}
case "name":
if (tmp.value == "yield" && !is_token(peek(), "punc", ":")
if (tmp.value == "yield" && !is_token(peek(), "punc", ":") && !is_token(peek(), "punc", "(")
&& S.input.has_directive("use strict") && !is_in_generator()) {
token_error(tmp, "Unexpected yield identifier inside strict mode");
}

View File

@@ -43,16 +43,17 @@
"use strict";
function SymbolDef(scope, index, orig) {
function SymbolDef(scope, orig) {
this.name = orig.name;
this.orig = [ orig ];
this.eliminated = 0;
this.scope = scope;
this.references = [];
this.replaced = 0;
this.global = false;
this.export = false;
this.mangled_name = null;
this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++;
};
@@ -344,7 +345,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
if (globals.has(name)) {
return globals.get(name);
} else {
var g = new SymbolDef(this, globals.size(), node);
var g = new SymbolDef(this, node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
@@ -415,7 +416,7 @@ AST_Scope.DEFMETHOD("def_function", function(symbol){
AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def;
if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol);
def = new SymbolDef(this, symbol);
this.variables.set(symbol.name, def);
def.global = !this.parent_scope;
} else {
@@ -433,7 +434,7 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling.
if (options.reserved.indexOf(m) >= 0) continue;
if (member(m, options.reserved)) continue;
// we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in
@@ -485,7 +486,7 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global;
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
options = defaults(options, {
eval : false,
ie8 : false,
@@ -495,15 +496,14 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
toplevel : false,
});
if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
push_uniq(options.reserved, "arguments");
return options;
});
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options);
// Never mangle arguments
options.reserved.push('arguments');
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of
@@ -512,11 +512,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var to_mangle = [];
if (options.cache) {
this.globals.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
});
this.globals.each(collect);
}
var tw = new TreeWalker(function(node, descend){
@@ -528,13 +524,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Scope) {
var p = tw.parent(), a = [];
node.variables.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
a.push(symbol);
}
});
to_mangle.push.apply(to_mangle, a);
node.variables.each(collect);
return;
}
if (node instanceof AST_Label) {
@@ -546,7 +536,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var mangle_with_block_scope =
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
if (mangle_with_block_scope && options.reserved.indexOf(node.name) < 0) {
to_mangle.push(node.definition());
return;
}
@@ -559,6 +549,74 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (options.cache) {
options.cache.cname = this.cname;
}
function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
}
});
AST_Toplevel.DEFMETHOD("find_unique_prefix", function(options) {
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
var cache = options.cache && options.cache.props;
var prefixes = Object.create(null);
options.reserved.forEach(add_prefix);
this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
}));
var prefix, i = 0;
do {
prefix = create_name(i++);
} while (prefixes[prefix]);
return prefix;
function add_prefix(name) {
if (/[0-9]$/.test(name)) {
prefixes[name.replace(/[0-9]+$/, "")] = true;
}
}
function add_def(def) {
var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
add_prefix(name);
}
function create_name(num) {
var name = "";
do {
name += letters[num % letters.length];
num = Math.floor(num / letters.length);
} while (num);
return name;
}
});
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
options = this._default_mangler_options(options);
var prefix = this.find_unique_prefix(options);
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
}));
function rename(def) {
if (def.global || def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return;
var d = def.redefined();
def.name = d ? d.name : prefix + def.id;
def.orig.forEach(function(sym) {
sym.name = def.name;
});
def.references.forEach(function(sym) {
sym.name = def.name;
});
}
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){

View File

@@ -262,11 +262,7 @@ TreeTransformer.prototype = new TreeWalker;
});
_(AST_TemplateString, function(self, tw) {
for (var i = 0; i < self.segments.length; i++) {
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
self.segments[i] = self.segments[i].transform(tw);
}
}
self.segments = do_list(self.segments, tw);
});
_(AST_PrefixedTemplateString, function(self, tw) {

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.1.1",
"version": "3.2.0",
"engines": {
"node": ">=0.8.0"
},
@@ -26,11 +26,11 @@
"LICENSE"
],
"dependencies": {
"commander": "~2.11.0",
"source-map": "~0.5.1"
"commander": "~2.12.1",
"source-map": "~0.6.1"
},
"devDependencies": {
"acorn": "~5.1.1",
"acorn": "~5.2.1",
"mocha": "~3.5.1",
"semver": "~5.4.1"
},

View File

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

View File

@@ -288,8 +288,10 @@ issue_2105_1: {
ecma: 6,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
unused: true,
}
input: {
@@ -313,17 +315,12 @@ issue_2105_1: {
});
}
expect: {
(() => {
var quux = () => {
({
prop() {
console.log;
console.log("PASS");
};
return {
prop() {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=4"
@@ -334,6 +331,7 @@ issue_2105_2: {
collapse_vars: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -359,17 +357,12 @@ issue_2105_2: {
});
}
expect: {
(() => {
var quux = () => {
({
prop: () => {
console.log;
console.log("PASS");
};
return {
prop: () => {
console.log;
quux();
}
};
})().prop();
}
}).prop();
}
expect_stdout: "PASS"
node_version: ">=6"
@@ -410,6 +403,7 @@ issue_2136_3: {
evaluate: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -437,6 +431,7 @@ call_args: {
ecma: 6,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -461,6 +456,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -508,6 +504,7 @@ issue_2084: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -630,3 +627,31 @@ issue_2271: {
}
expect_stdout: "PASS"
}
concise_method_with_super: {
options = {
arrows: true,
}
input: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -104,3 +104,65 @@ asm_mixed: {
}
}
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}

View File

@@ -141,6 +141,7 @@ async_inline: {
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -202,6 +202,7 @@ dead_code_const_declaration: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
};
input: {
@@ -229,6 +230,7 @@ dead_code_const_annotation: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
toplevel : true,
};
@@ -281,6 +283,7 @@ dead_code_const_annotation_complex_scope: {
booleans : true,
conditionals : true,
evaluate : true,
reduce_funcs : true,
reduce_vars : true,
toplevel : true,
};
@@ -439,6 +442,7 @@ global_timeout_and_interval_symbols: {
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
@@ -470,6 +474,7 @@ issue_2233_2: {
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -560,3 +565,64 @@ global_fns: {
"RangeError",
]
}
issue_2383_1: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
if (0) {
var {x, y} = foo();
}
}
expect: {
var x, y;
}
}
issue_2383_2: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
if (0) {
var {
x = 0,
y: [ w, , { z, p: q = 7 } ] = [ 1, 2, { z: 3 } ]
} = {};
}
console.log(x, q, w, z);
}
expect: {
var x, w, z, q;
console.log(x, q, w, z);
}
expect_stdout: "undefined undefined undefined undefined"
node_version: ">=6"
}
issue_2383_3: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
var b = 7, y = 8;
if (0) {
var a = 1, [ x, y, z ] = [ 2, 3, 4 ], b = 5;
}
console.log(a, x, y, z, b);
}
expect: {
var b = 7, y = 8;
var a, x, y, z, b;
console.log(a, x, y, z, b);
}
expect_stdout: "undefined undefined 8 undefined 7"
node_version: ">=6"
}

View File

@@ -262,6 +262,7 @@ destructuring_dont_evaluate_with_undefined_as_default_assignment: {
reduce_vars: {
options = {
reduce_funcs: true,
reduce_vars: true,
}
input: {

View File

@@ -733,6 +733,7 @@ drop_value: {
const_assign: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -785,6 +786,7 @@ issue_1539: {
vardef_value: {
options = {
keep_fnames: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -846,6 +848,7 @@ assign_chain: {
issue_1583: {
options = {
keep_fargs: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -863,12 +866,12 @@ issue_1583: {
expect: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
t = function() {
return (function(a) {
return function(a) {};
})();
}();
})();
}
}
}
@@ -1200,6 +1203,7 @@ var_catch_toplevel: {
options = {
conditionals: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -1291,15 +1295,15 @@ issue_2063: {
}
expect: {
var a;
var a;
}
}
issue_2105: {
issue_2105_1: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -1325,17 +1329,51 @@ issue_2105: {
});
}
expect: {
(function() {
var quux = function() {
({
prop: function() {
console.log;
console.log("PASS");
};
return {
prop: function() {
console.log;
quux();
}
}).prop();
}
expect_stdout: "PASS"
}
issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
properties: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
};
})().prop();
return bar;
} );
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
@@ -1390,6 +1428,7 @@ issue_2136_3: {
evaluate: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -1535,3 +1574,101 @@ issue_2288: {
}
}
}
issue_2418_1: {
options = {
unused: true,
}
input: {
class C {}
function F() {}
(class c {});
(function f() {});
}
expect: {
class C {}
function F() {}
(class {});
(function() {});
}
}
issue_2418_2: {
options = {
keep_classnames: false,
keep_fnames: false,
unused: true,
}
input: {
class C {}
function F() {}
(class c {});
(function f() {});
}
expect: {
class C {}
function F() {}
(class {});
(function() {});
}
}
issue_2418_3: {
options = {
keep_classnames: false,
keep_fnames: true,
unused: true,
}
input: {
class C {}
function F() {}
(class c {});
(function f() {});
}
expect: {
class C {}
function F() {}
(class {});
(function f() {});
}
}
issue_2418_4: {
options = {
keep_classnames: true,
keep_fnames: false,
unused: true,
}
input: {
class C {}
function F() {}
(class c {});
(function f() {});
}
expect: {
class C {}
function F() {}
(class c {});
(function() {});
}
}
issue_2418_5: {
options = {
keep_classnames: true,
keep_fnames: true,
unused: true,
}
input: {
class C {}
function F() {}
(class c {});
(function f() {});
}
expect: {
class C {}
function F() {}
(class c {});
(function f() {});
}
}

View File

@@ -345,6 +345,7 @@ unsafe_constant: {
unsafe_object: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -373,6 +374,7 @@ unsafe_object: {
unsafe_object_nested: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -401,6 +403,7 @@ unsafe_object_nested: {
unsafe_object_complex: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -429,6 +432,7 @@ unsafe_object_complex: {
unsafe_object_repeated: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
@@ -457,6 +461,7 @@ unsafe_object_repeated: {
unsafe_object_accessor: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe: true,
}
@@ -480,10 +485,11 @@ unsafe_object_accessor: {
}
}
unsafe_function: {
prop_function: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
properties: true,
side_effects: true,
}
input: {
console.log(
@@ -496,9 +502,9 @@ unsafe_function: {
expect: {
console.log(
({a:{b:1},b:function(){}}) + 1,
({b:function(){}}, {b:1}) + 1,
({a:{b:1}}, function(){}) + 1,
({b:function(){}}, {b:1}).b + 1
({b:1}) + 1,
function(){} + 1,
2
);
}
expect_stdout: true
@@ -724,10 +730,11 @@ unsafe_string_bad_index: {
expect_stdout: true
}
unsafe_prototype_function: {
prototype_function: {
options = {
evaluate : true,
unsafe : true
evaluate: true,
properties: true,
side_effects: true,
}
input: {
var a = ({valueOf: 0}) < 1;
@@ -746,8 +753,8 @@ unsafe_prototype_function: {
var d = ({toString: 0}) + "";
var e = (({valueOf: 0}) + "")[2];
var f = (({toString: 0}) + "")[2];
var g = ({}, 0)();
var h = ({}, 0)();
var g = 0();
var h = 0();
}
}
@@ -755,6 +762,7 @@ call_args: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
@@ -777,6 +785,7 @@ call_args_drop_param: {
evaluate: true,
inline: true,
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -1107,6 +1116,7 @@ Infinity_NaN_undefined_LHS: {
issue_1964_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: false,
unused: true,
@@ -1114,6 +1124,7 @@ issue_1964_1: {
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
@@ -1121,16 +1132,21 @@ issue_1964_1: {
expect: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect_stdout: "b"
expect_stdout: [
"\\s",
"b",
]
}
issue_1964_2: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: true,
unused: true,
@@ -1138,17 +1154,22 @@ issue_1964_2: {
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
console.log(/\s/.source);
return "a b c".split(/\s/)[1];
}
console.log(f());
}
expect_stdout: "b"
expect_stdout: [
"\\s",
"b",
]
}
array_slice_index: {
@@ -1278,3 +1299,42 @@ issue_2231_2: {
}
expect_stdout: true
}
self_comparison_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}
self_comparison_2: {
options = {
evaluate: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}

View File

@@ -124,6 +124,7 @@ async_func: {
issue_2134_1: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -141,6 +142,7 @@ issue_2134_1: {
issue_2134_2: {
options = {
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -226,3 +228,37 @@ keyword_valid_3: {
export { default as default } from "module.js";
}
}
dynamic_import: {
mangle = {
toplevel: true,
}
input: {
import traditional from './traditional.js';
function imp(x) {
return import(x);
}
import("module_for_side_effects.js");
let dynamic = import("some/module.js");
dynamic.foo();
}
expect: {
import o from "./traditional.js";
function t(o) {
return import(o);
}
import("module_for_side_effects.js");
let r = import("some/module.js");
r.foo();
}
}
trailing_comma: {
beautify = {
beautify: true,
}
input: {
export const a = 1;
}
expect_exact: "export const a = 1;"
}

View File

@@ -19,6 +19,7 @@ iifes_returning_constants_keep_fargs_true: {
booleans : true,
if_return : true,
join_vars : true,
reduce_funcs : true,
reduce_vars : true,
cascade : true,
inline : true,
@@ -55,6 +56,7 @@ iifes_returning_constants_keep_fargs_false: {
booleans : true,
if_return : true,
join_vars : true,
reduce_funcs : true,
reduce_vars : true,
cascade : true,
inline : true,
@@ -101,6 +103,7 @@ issue_1841_1: {
options = {
keep_fargs: false,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -127,6 +130,7 @@ issue_1841_2: {
options = {
keep_fargs: false,
pure_getters: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -151,13 +155,14 @@ issue_1841_2: {
function_returning_constant_literal: {
options = {
reduce_vars: true,
unsafe: true,
toplevel: true,
evaluate: true,
cascade: true,
unused: true,
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function greeter() {
@@ -305,6 +310,7 @@ issue_2084: {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -340,6 +346,7 @@ issue_2084: {
issue_2097: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -508,3 +515,42 @@ issue_2114_2: {
}
expect_stdout: "2"
}
issue_2428: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function bar(k) {
console.log(k);
}
function foo(x) {
return bar(x);
}
function baz(a) {
foo(a);
}
baz(42);
baz("PASS");
}
expect: {
function baz(a) {
console.log(a);
}
baz(42);
baz("PASS");
}
expect_stdout: [
"42",
"PASS",
]
}

View File

@@ -736,6 +736,7 @@ object_spread_unsafe: {
evaluate: true,
join_vars: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -804,3 +805,350 @@ object_spread_of_sequence: {
console.log({ ...o || o });
}
}
// issue 2316
class_name_can_be_preserved_with_reserved: {
mangle = {
reserved: [ "Foo" ],
}
input: {
function x() {
class Foo {}
Foo.bar;
class Bar {}
Bar.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var Bar = class Bar {};
Bar.bar;
}
}
expect: {
function x() {
class Foo {}
Foo.bar;
class a {}
a.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var a = class a {};
a.bar;
}
}
}
issue_2345: {
options = {
evaluate: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
console.log([...[3, 2, 1]].join("-"));
var a = [3, 2, 1];
console.log([...a].join("-"));
}
expect: {
console.log([...[3, 2, 1]].join("-"));
var a = [3, 2, 1];
console.log([...a].join("-"));
}
expect_stdout: [
"3-2-1",
"3-2-1",
]
node_version: ">=6"
}
issue_2349: {
mangle = {}
input: {
function foo(boo, key) {
const value = boo.get();
return value.map(({[key]: bar}) => bar);
}
console.log(foo({
get: () => [ {
blah: 42
} ]
}, "blah"));
}
expect: {
function foo(o, n) {
const t = o.get();
return t.map(({[n]: o}) => o);
}
console.log(foo({
get: () => [ {
blah: 42
} ]
}, "blah"));
}
expect_stdout: [
"[ 42 ]",
]
node_version: ">=7"
}
issue_2349b: {
options = {
arrows: true,
collapse_vars: true,
ecma: 6,
evaluate: true,
inline: true,
passes: 3,
properties: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
side_effects: true,
unsafe_arrows: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
function foo(boo, key) {
const value = boo.get();
return value.map(function({[key]: bar}){ return bar; });
}
console.log(foo({
get: function() {
return [ {
blah: 42
} ];
}
}, "blah"));
}
expect: {
console.log([ {
blah: 42
} ].map(({["blah"]: l}) => l));
}
expect_stdout: [
"[ 42 ]",
]
node_version: ">=7"
}
shorthand_keywords: {
beautify = {
ecma: 6,
}
input: {
var foo = 0,
async = 1,
await = 2,
implements = 3,
package = 4,
private = 5,
protected = 6,
static = 7,
yield = 8;
console.log({
foo: foo,
0: 0,
NaN: NaN,
async: async,
await: await,
false: false,
implements: implements,
null: null,
package: package,
private: private,
protected: protected,
static: static,
this: this,
true: true,
undefined: undefined,
yield: yield,
});
}
expect_exact: "var foo=0,async=1,await=2,implements=3,package=4,private=5,protected=6,static=7,yield=8;console.log({foo,0:0,NaN:NaN,async,await,false:false,implements:implements,null:null,package:package,private:private,protected:protected,static:static,this:this,true:true,undefined:void 0,yield});"
expect_stdout: true
node_version: ">=4"
}
array_literal_with_spread_1: {
options = {
properties: true,
side_effects: true,
}
input: {
var f = (x) => [...x][0];
console.log(f(["PASS"]));
}
expect: {
var f = x => [ ...x ][0];
console.log(f([ "PASS" ]));
}
expect_stdout: "PASS"
node_version: ">=6"
}
array_literal_with_spread_2: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log([10, ...[], 20, ...[30, 40], 50]["length"]);
console.log([10, ...[], 20, ...[30, 40], 50][0]);
console.log([10, ...[], 20, ...[30, 40], 50][1]);
console.log([10, ...[], 20, ...[30, 40], 50][2]);
console.log([10, ...[], 20, ...[30, 40], 50][3]);
console.log([10, ...[], 20, ...[30, 40], 50][4]);
console.log([10, ...[], 20, ...[30, 40], 50][5]);
}
expect: {
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ]["length"]);
console.log(10);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][1]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][2]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][3]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][4]);
console.log([ 10, ...[], 20, ...[ 30, 40 ], 50 ][5]);
}
expect_stdout: [
"5",
"10",
"20",
"30",
"40",
"50",
"undefined",
]
node_version: ">=6"
}
array_literal_with_spread_3: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log([10, 20][0]);
console.log([10, 20][1]);
console.log([10, 20][2]);
console.log([...[], 10, 20][0]);
console.log([...[], 10, 20][1]);
console.log([...[], 10, 20][2]);
console.log([10, ...[], 20][0]);
console.log([10, ...[], 20][1]);
console.log([10, ...[], 20][2]);
console.log([10, 20, ...[]][0]);
console.log([10, 20, ...[]][1]);
console.log([10, 20, ...[]][2]);
}
expect: {
console.log(10);
console.log(20);
console.log([ 10, 20 ][2]);
console.log([...[], 10, 20][0]);
console.log([...[], 10, 20][1]);
console.log([...[], 10, 20][2]);
console.log(10);
console.log([10, ...[], 20][1]);
console.log([10, ...[], 20][2]);
console.log(10);
console.log(20);
console.log([10, 20, ...[]][2]);
}
expect_stdout: [
"10",
"20",
"undefined",
"10",
"20",
"undefined",
"10",
"20",
"undefined",
"10",
"20",
"undefined",
]
node_version: ">=6"
}
array_literal_with_spread_4: {
options = {
properties: true,
side_effects: true,
}
input: {
function t(x) {
console.log("(" + x + ")");
return 10 * x;
}
console.log([t(1), t(2)][0]);
console.log([t(1), t(2)][1]);
console.log([t(1), t(2)][2]);
console.log([...[], t(1), t(2)][0]);
console.log([...[], t(1), t(2)][1]);
console.log([...[], t(1), t(2)][2]);
console.log([t(1), ...[], t(2)][0]);
console.log([t(1), ...[], t(2)][1]);
console.log([t(1), ...[], t(2)][2]);
console.log([t(1), t(2), ...[]][0]);
console.log([t(1), t(2), ...[]][1]);
console.log([t(1), t(2), ...[]][2]);
}
expect: {
function t(x) {
console.log("(" + x + ")");
return 10 * x;
}
console.log([ t(1), t(2) ][0]);
console.log((t(1), t(2)));
console.log([ t(1), t(2) ][2]);
console.log([ ...[], t(1), t(2) ][0]);
console.log([ ...[], t(1), t(2) ][1]);
console.log([ ...[], t(1), t(2) ][2]);
console.log([ t(1), t(2) ][0]);
console.log([ t(1), ...[], t(2) ][1]);
console.log([ t(1), ...[], t(2) ][2]);
console.log([ t(1), t(2) ][0]);
console.log((t(1), t(2)));
console.log([ t(1), t(2), ...[] ][2]);
}
expect_stdout: [
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
"(1)", "(2)", "10",
"(1)", "(2)", "20",
"(1)", "(2)", "undefined",
]
node_version: ">=6"
}

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ f7: {
negate_iife: true,
passes: 3,
properties: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
iife_for: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -26,6 +27,7 @@ iife_for: {
iife_for_in: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -51,6 +53,7 @@ iife_for_in: {
iife_do: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -80,6 +83,7 @@ iife_do: {
iife_while: {
options = {
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,

View File

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

View File

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

View File

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

View File

@@ -126,6 +126,67 @@ computed_property_names: {
expect_exact: 'obj({["x"+"x"]:6});'
}
convert_computed_props_to_regular_ones: {
options = {
booleans: true,
computed_props: true,
evaluate: true,
}
input: {
var o = {
["hi"]: 0,
["A" + 1]: 1,
[/B/]: 2,
[100 + 23]: 3,
[1 + .5]: 4,
[Math.PI]: 5,
[undefined]: 6,
[true]: 7,
[false]: 8,
[null]: 9,
[Infinity]: 10,
[NaN]: 11,
};
for (var k in o) {
console.log(k, o[k]);
}
}
expect: {
var o = {
hi: 0,
A1: 1,
[/B/]: 2,
123: 3,
1.5: 4,
[Math.PI]: 5,
// leave these problematic cases as is
[void 0]: 6,
[!0]: 7,
[!1]: 8,
[null]: 9,
[1 / 0]: 10,
[NaN]: 11
};
for (var k in o) console.log(k, o[k]);
}
expect_stdout: [
"123 3",
"hi 0",
"A1 1",
"/B/ 2",
"1.5 4",
"3.141592653589793 5",
"undefined 6",
"true 7",
"false 8",
"null 9",
"Infinity 10",
"NaN 11",
]
node_version: ">=6"
}
computed_property_names_evaluated_1: {
options = {
evaluate: true
@@ -516,6 +577,7 @@ variable_as_computed_property: {
prop_func_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -544,6 +606,7 @@ prop_func_to_concise_method: {
prop_arrow_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -592,6 +655,7 @@ concise_method_to_prop_arrow: {
prop_func_to_async_concise_method: {
options = {
ecma: 8,
unsafe_methods: true,
}
input: {
({
@@ -614,6 +678,7 @@ prop_func_to_async_concise_method: {
prop_func_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -646,6 +711,7 @@ prop_func_to_concise_method_various: {
prop_arrows_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -674,6 +740,7 @@ prop_arrows_to_concise_method_various: {
prop_arrow_with_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {
@@ -711,6 +778,7 @@ prop_arrow_with_this: {
prop_arrow_with_nested_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {

View File

@@ -1,7 +1,8 @@
keep_properties: {
options = {
properties: false
};
evaluate: true,
properties: false,
}
input: {
a["foo"] = "bar";
}
@@ -12,6 +13,7 @@ keep_properties: {
dot_properties: {
options = {
evaluate: true,
properties: true,
}
beautify = {
@@ -37,6 +39,7 @@ dot_properties: {
dot_properties_es5: {
options = {
evaluate: true,
properties: true,
}
beautify = {
@@ -61,8 +64,8 @@ dot_properties_es5: {
sub_properties: {
options = {
evaluate: true,
properties: true
};
properties: true,
}
input: {
a[0] = 0;
a["0"] = 1;
@@ -81,18 +84,18 @@ sub_properties: {
a[3.14] = 3;
a.if = 4;
a["foo bar"] = 5;
a[NaN] = 6;
a[null] = 7;
a.NaN = 6;
a.null = 7;
a[void 0] = 8;
}
}
evaluate_array_length: {
options = {
evaluate: true,
properties: true,
unsafe: true,
evaluate: true
};
}
input: {
a = [1, 2, 3].length;
a = [1, 2, 3].join()["len" + "gth"];
@@ -109,10 +112,10 @@ evaluate_array_length: {
evaluate_string_length: {
options = {
evaluate: true,
properties: true,
unsafe: true,
evaluate: true
};
}
input: {
a = "foo".length;
a = ("foo" + "bar")["len" + "gth"];
@@ -151,7 +154,8 @@ mangle_properties: {
mangle_unquoted_properties: {
options = {
properties: false
evaluate: true,
properties: false,
}
mangle = {
properties: {
@@ -250,7 +254,8 @@ mangle_debug_suffix: {
mangle_debug_suffix_keep_quoted: {
options = {
properties: false
evaluate: true,
properties: false,
}
mangle = {
properties: {
@@ -679,8 +684,8 @@ accessor_this: {
issue_2208_1: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
@@ -698,8 +703,8 @@ issue_2208_1: {
issue_2208_2: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
@@ -723,8 +728,8 @@ issue_2208_2: {
issue_2208_3: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
a = 42;
@@ -748,8 +753,8 @@ issue_2208_3: {
issue_2208_4: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
function foo() {}
@@ -772,8 +777,8 @@ issue_2208_4: {
issue_2208_5: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
@@ -792,8 +797,8 @@ issue_2208_5: {
issue_2208_6: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
console.log({
@@ -809,9 +814,11 @@ issue_2208_6: {
issue_2208_7: {
options = {
ecma: 6,
inline: true,
properties: true,
side_effects: true,
unsafe: true,
unsafe_arrows: true,
}
input: {
console.log({
@@ -829,9 +836,11 @@ issue_2208_7: {
issue_2208_8: {
options = {
ecma: 6,
inline: true,
properties: true,
side_effects: true,
unsafe: true,
unsafe_arrows: true,
}
input: {
console.log({
@@ -851,17 +860,17 @@ issue_2208_8: {
return x();
}
}.p());
console.log(async function() {
console.log((async () => {
return await x();
}());
})());
}
}
issue_2208_9: {
options = {
inline: true,
properties: true,
side_effects: true,
unsafe: true,
}
input: {
a = 42;
@@ -887,6 +896,7 @@ methods_keep_quoted_true: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -906,6 +916,7 @@ methods_keep_quoted_false: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -929,8 +940,10 @@ methods_keep_quoted_from_dead_code: {
dead_code: true,
ecma: 6,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -964,3 +977,357 @@ issue_2256: {
g.keep = g.g;
}
}
issue_2321: {
options = {
ecma: 6,
unsafe_methods: false,
}
input: {
var f = {
foo: function(){ console.log("foo") },
bar() { console.log("bar") }
};
var foo = new f.foo();
var bar = f.bar();
}
expect: {
var f = {
foo: function() {
console.log("foo");
},
bar() {
console.log("bar");
}
};
var foo = new f.foo();
var bar = f.bar();
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=6"
}
unsafe_methods_regex: {
options = {
ecma: 6,
unsafe_methods: /^[A-Z1]/,
}
input: {
var f = {
123: function(){ console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar") },
Baz: function(){ console.log("baz") },
BOO: function(){ console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect: {
var f = {
123() { console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar"); },
Baz() { console.log("baz") },
BOO() { console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect_stdout: [
"123",
"foo",
"bar",
"baz",
"boo",
"null",
"undefined",
]
node_version: ">=6"
}
lhs_prop_1: {
options = {
evaluate: true,
properties: true,
}
input: {
console.log(++{
a: 1
}.a);
}
expect: {
console.log(++{
a: 1
}.a);
}
expect_stdout: "2"
}
lhs_prop_2: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
[1][0] = 42;
(function(a) {
a.b = "g";
})("abc");
(function(a) {
a[2] = "g";
})("def");
(function(a) {
a[""] = "g";
})("ghi");
}
expect: {
[1][0] = 42;
"abc".b = "g";
"def"[2] = "g";
"ghi"[""] = "g";
}
}
literal_duplicate_key_side_effects: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log({
a: "FAIL",
a: console.log ? "PASS" : "FAIL"
}.a);
}
expect: {
console.log(console.log ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
prop_side_effects_1: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
bar: function() {
return C + C;
}
};
console.log(obj.bar());
}
expect: {
console.log(1);
var obj = {
bar: function() {
return 2;
}
};
console.log(obj.bar());
}
expect_stdout: [
"1",
"2",
]
}
prop_side_effects_2: {
options = {
evaluate: true,
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
"": function() {
return C + C;
}
};
console.log(obj[""]());
}
expect: {
console.log(1);
console.log(2);
}
expect_stdout: [
"1",
"2",
]
}
accessor_1: {
options = {
properties: true,
}
input: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect_stdout: "PASS"
node_version: ">=4"
}
accessor_2: {
options = {
properties: true,
}
input: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect_stdout: true
}
array_hole: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log(
[ 1, 2, , 3][1],
[ 1, 2, , 3][2],
[ 1, 2, , 3][3]
);
}
expect: {
console.log(2, void 0, 3);
}
expect_stdout: "2 undefined 3"
}
computed_property: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log({
a: "bar",
[console.log("foo")]: 42,
}.a);
}
expect: {
console.log([
"bar",
console.log("foo")
][0]);
}
expect_stdout: [
"foo",
"bar"
]
node_version: ">=4"
}
new_this: {
options = {
properties: true,
side_effects: true,
}
input: {
new {
f: function(a) {
this.a = a;
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
}
issue_2513: {
options = {
evaluate: true,
properties: true,
}
input: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"["Infinity"]);
console.log("c"[0/0], "d"["NaN"]);
console.log("e"[void 0], "f"["undefined"]);
}(0, 0, 0);
}
expect: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"[1/0]);
console.log("c".NaN, "d".NaN);
console.log("e"[void 0], "f"[void 0]);
}(0, 0, 0);
}
expect_stdout: [
"undefined undefined",
"undefined undefined",
"undefined undefined",
]
}

View File

@@ -1,6 +1,7 @@
strict: {
options = {
pure_getters: "strict",
reduce_funcs: false,
reduce_vars: false,
side_effects: true,
toplevel: true,
@@ -30,6 +31,7 @@ strict: {
strict_reduce_vars: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -58,6 +60,7 @@ strict_reduce_vars: {
unsafe: {
options = {
pure_getters: true,
reduce_funcs: false,
reduce_vars: false,
side_effects: true,
toplevel: true,
@@ -84,6 +87,7 @@ unsafe: {
unsafe_reduce_vars: {
options = {
pure_getters: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -185,6 +189,7 @@ issue_2110_1: {
pure_getters: "strict",
sequences: true,
side_effects: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -215,6 +220,7 @@ issue_2110_2: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -247,6 +253,7 @@ set_immutable_1: {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -270,6 +277,7 @@ set_immutable_2: {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -293,6 +301,7 @@ set_immutable_3: {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -318,6 +327,7 @@ set_immutable_4: {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -343,6 +353,7 @@ set_mutable_1: {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
@@ -367,6 +378,7 @@ set_mutable_2: {
cascade: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -403,6 +415,7 @@ issue_2265_1: {
issue_2265_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -428,6 +441,7 @@ issue_2265_2: {
issue_2265_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -447,6 +461,7 @@ issue_2265_3: {
issue_2265_4: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,

File diff suppressed because it is too large Load Diff

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

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

View File

@@ -187,6 +187,7 @@ dont_screw_try_catch_undefined: {
reduce_vars: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
ie8: true,
unused: true,

View File

@@ -714,6 +714,7 @@ issue_1705_2: {
options = {
dead_code: true,
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,

View File

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

View File

@@ -10,7 +10,7 @@ function read(path) {
describe("bin/uglifyjs", function () {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("should produce a functional build when using --self", function (done) {
this.timeout(60000);
this.timeout(120000);
var command = uglifyjscmd + ' --self -mc ecma=';
command += semver.satisfies(process.version, ">=4") ? "6" : "5";

View File

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

View File

@@ -73,6 +73,13 @@ describe("minify", function() {
assert.strictEqual(run_code(compressed), run_code(original));
});
it("should not parse invalid use of reserved words", function() {
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
assert.strictEqual(Uglify.minify("function super(){}").error.message, "Unexpected token: name (super)");
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
});
describe("keep_quoted_props", function() {
it("Should preserve quotes in object literals", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
@@ -321,4 +328,37 @@ describe("minify", function() {
});
});
});
describe("collapse_vars", function() {
it("Should not produce invalid AST", function() {
var code = [
"function f(a) {",
" a = x();",
" return a;",
"}",
"f();",
].join("\n");
var ast = Uglify.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
},
}).ast;
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 2);
assert.strictEqual(ast.body[0].TYPE, "Defun");
assert.strictEqual(ast.body[0].body.length, 2);
assert.strictEqual(ast.body[0].body[0].TYPE, "SimpleStatement");
var stat = ast.body[0].body[0];
Uglify.minify(ast, {
compress: {
sequences: false
},
mangle: false
});
assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()");
});
});
});

View File

@@ -102,4 +102,15 @@ describe("Yield", function() {
assert.throws(test(tests[i]), fail, tests[i]);
}
});
it("Should allow yield to be used as class/object property name", function() {
var input = [
'"use strict";',
"({yield:42});",
"({yield(){}});",
"(class{yield(){}});",
"class C{yield(){}}",
].join("");
assert.strictEqual(UglifyJS.minify(input, { compress: false }).code, input);
});
});

View File

@@ -117,6 +117,10 @@ function run_compress_tests() {
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
}
if (test.rename) {
input.figure_out_scope(test.mangle);
input.expand_names(test.mangle);
}
var cmp = new U.Compressor(options, true);
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);

View File

@@ -162,6 +162,7 @@ var VALUES = [
'"object"',
'"number"',
'"function"',
'this',
];
var BINARY_OPS_NO_COMMA = [
@@ -349,10 +350,10 @@ function createParams() {
return params.join(', ');
}
function createArgs() {
function createArgs(recurmax, stmtDepth, canThrow) {
var args = [];
for (var n = rng(4); --n >= 0;) {
args.push(createValue());
args.push(rng(2) ? createValue() : createExpression(recurmax - 1, COMMA_OK, stmtDepth, canThrow));
}
return args.join(', ');
}
@@ -390,9 +391,10 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
VAR_NAMES.length = namesLenBefore;
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');';
if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s;
// avoid "function statements" (decl inside statements)
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name;
s += '(' + createArgs(recurmax, stmtDepth, canThrow) + ');';
return s;
}
@@ -626,6 +628,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
case p++:
case p++:
return createValue();
case p++:
case p++:
return getVarName();
case p++:
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
case p++:

View File

@@ -16,11 +16,9 @@
{},
{
"compress": {
"toplevel": true
"hoist_props": true
},
"mangle": {
"toplevel": true
}
"toplevel": true
},
{
"compress": {