Compare commits

...

57 Commits

Author SHA1 Message Date
Alex Lam S.L
f8ff349ba7 harmony-v3.2.2 2017-12-11 00:16:36 +08:00
alexlamsl
f2b179ae94 fix escape analysis for AST_Expansion 2017-12-10 23:05:22 +08:00
alexlamsl
c7e8fc4830 fix escape analysis for `AST_Await
fixes #2566
2017-12-10 23:03:29 +08:00
alexlamsl
f778a0aa01 fix escape analysis for AST_Yield
fixes #2565
2017-12-10 23:02:20 +08:00
alexlamsl
7fd4b66eaa fix tests 2017-12-10 14:16:54 +08:00
alexlamsl
21c986ff5b Merge branch 'master' into harmony-v3.2.2 2017-12-10 14:12:24 +08:00
Alex Lam S.L
2441827408 v3.2.2 2017-12-10 13:46:17 +08:00
Alex Lam S.L
0aff037a35 improve unused on assign-only symbols (#2568) 2017-12-09 06:19:29 +08:00
Alex Lam S.L
74a2f53683 fix escape analysis for AST_Throw (#2564) 2017-12-08 02:54:37 +08:00
Alex Lam S.L
e20935c3f2 fix escape analysis for AST_Conditional & AST_Sequence (#2563)
fixes #2560
2017-12-08 01:50:38 +08:00
Alex Lam S.L
3e34f62a1c account for side-effects in conditional call inversion (#2562)
fixes #2560
2017-12-08 01:15:31 +08:00
Alex Lam S.L
d21cb84696 eliminate noop calls more aggressively (#2559) 2017-12-07 01:22:08 +08:00
Alex Lam S.L
3dd495ecdd improve if_return (#2558)
`return void x()` => `x()`
2017-12-07 01:01:52 +08:00
Alex Lam S.L
87bae623e9 simplify computed properties for methods, getters & setters (#2555)
fixes #2554
2017-12-04 00:18:48 +08:00
Alex Lam S.L
606f7a5b37 harmony-v3.2.1 2017-12-03 13:51:27 +08:00
alexlamsl
b91a2e018a fix tests 2017-12-03 12:14:31 +08:00
alexlamsl
c9dbe9deb1 Merge branch 'master' into harmony-v3.2.1 2017-12-03 11:59:41 +08:00
Alex Lam S.L
b9f3ddfb30 v3.2.1 2017-12-03 11:39:51 +08:00
Alex Lam S.L
77332a0315 fix dead_code on for (#2552) 2017-12-02 15:46:05 +08:00
Alex Lam S.L
85c56adbd1 more tests for #2535 (#2551) 2017-12-02 02:26:56 +08:00
Alex Lam S.L
8da3754e51 improve evaluate on typeof (#2550)
- gated through `typeofs`
2017-12-02 02:18:33 +08:00
Alex Lam S.L
9a6b11f8e6 improve boolean compression (#2548)
fixes #2535
2017-12-01 22:41:35 +08:00
Alex Lam S.L
7ac6fdcc99 improve switch case compression (#2547) 2017-12-01 14:32:00 +08:00
Alex Lam S.L
f6610baaa8 improve AST_For.init & AST_Switch.expression compression (#2546) 2017-12-01 12:53:59 +08:00
Alex Lam S.L
09b320e8a5 convert to number under boolean context (#2545) 2017-12-01 12:52:36 +08:00
Alex Lam S.L
5a1e99d713 improve compression of if conditions (#2544) 2017-12-01 06:18:31 +08:00
Alex Lam S.L
b762f2d6f4 improve compression of loop conditions (#2543) 2017-12-01 05:52:33 +08:00
Alex Lam S.L
172079a47f improve code reuse (#2542) 2017-12-01 03:40:46 +08:00
Alex Lam S.L
c58d3936a3 fix corner case in call binding (#2541) 2017-12-01 03:18:20 +08:00
Alex Lam S.L
18302bf8e9 backport test from #2526 (#2534) 2017-11-29 13:32:00 +08:00
Alex Lam S.L
bc5047c1e7 fix inline on nested substitutions (#2533)
fixes #2531
2017-11-29 13:31:41 +08:00
kzc
1885f91f13 document top level minify() option safari10 (#2532) 2017-11-29 05:48:33 +08:00
Alex Lam S.L
736c366d93 introduce --safari10 (#2530) 2017-11-29 03:34:47 +08:00
kzc
1646c5844f document the new output option safari10 (#2529) 2017-11-29 02:29:23 +08:00
Alex Lam S.L
aacf760fb4 add Safari workaround for await (#2528)
fixes #2344
2017-11-29 00:20:36 +08:00
Alex Lam S.L
755e2a62c6 extend hoist_props to AST_Arrow & AST_Class (#2527)
fixes #2503
2017-11-28 22:54:44 +08:00
Alex Lam S.L
62d2817d6c reduce this in block scopes (#2526)
fixes #2455
2017-11-28 22:54:21 +08:00
Alex Lam S.L
37cbd7080c replace single-use class definitions (#2524)
fixes #2416
2017-11-28 20:57:15 +08:00
Alex Lam S.L
206a54a746 fix nested hoist_props substitution (#2523)
fixes #2519
2017-11-28 14:39:00 +08:00
Alex Lam S.L
32def5ebf5 improve synergy between collapse_vars & unused (#2521) 2017-11-28 14:02:39 +08:00
Alex Lam S.L
ecc9f6b770 drop assignment in AST_VarDef.value (#2522)
fixes #2516
2017-11-28 13:08:40 +08:00
Alex Lam S.L
b84c99ef5c harmony-v3.2.0 2017-11-26 06:02:49 +08:00
alexlamsl
4f08c2f504 Merge branch 'master' into harmony-v3.2.0 2017-11-26 04:23:57 +08:00
Alex Lam S.L
b37a68c84f v3.2.0 2017-11-26 04:08:35 +08:00
Alex Lam S.L
c141ae6f8d fix argument/atom collision by properties (#2514)
fixes #2513
2017-11-25 22:52:46 +08:00
Alex Lam S.L
97c464dbf5 fix wording and formatting (#2512) 2017-11-25 19:07:46 +08:00
kzc
ba4894af18 document top level minify option keep_classnames (#2511) 2017-11-25 16:33:03 +08:00
Alex Lam S.L
f1e3ef5262 separate keep_classnames & keep_fnames (#2510)
fixes #2418
2017-11-25 16:31:52 +08:00
Alex Lam S.L
3b28b915eb extend escape analysis on constant expression properties (#2509)
fixes #2508
2017-11-24 14:07:39 +08:00
Alex Lam S.L
eb001dc1d9 fix argument/atom collision by collapse_vars (#2507)
fixes #2506
2017-11-24 07:26:22 +08:00
Alex Lam S.L
aa9bdf416e make AST_Lambda.contains_this() less magical (#2505) 2017-11-24 07:03:37 +08:00
Alex Lam S.L
bbf38dc9c0 fix reduce_vars on arrow functions with this (#2504)
fixes #2496
2017-11-24 06:21:49 +08:00
Alex Lam S.L
8987780db6 eliminate invalid state caching in collapse_vars (#2502)
fixes #2497
2017-11-24 04:12:37 +08:00
Alex Lam S.L
30cfea2e7a fix rename (#2501)
- suppress spurious `rename` from `commander`
- handle `AST_SymbolCatch` correctly
2017-11-24 03:05:43 +08:00
kzc
3d8341a7ab fix properties for array literal with spread (#2499)
fixes #2498
2017-11-24 02:04:26 +08:00
Alex Lam S.L
f4e2fb9864 expand symbol space to improve compression (#2460)
- give globally distinct names to distinct variables
- improve ability to compress cross-scoped
- introduce `options.rename` to `minify()`
- default `true` if both `compress` & `mangle`
2017-11-19 19:29:51 +08:00
Alex Lam S.L
b80062c490 enable hoist_props by default (#2492) 2017-11-19 14:56:23 +08:00
42 changed files with 3360 additions and 564 deletions

110
README.md
View File

@@ -107,9 +107,15 @@ a double dash to prevent input files being used as option arguments:
Equivalent to setting `ie8: true` in `minify()` Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options. for `compress`, `mangle` and `output` options.
By default UglifyJS will not try to be IE-proof. 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 --keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name. code relying on Function.prototype.name.
--name-cache <file> File to hold mangled name mappings. --name-cache <file> File to hold mangled name mappings.
--safari10 Support non-standard Safari 10/11.
Equivalent to setting `safari10: true` in `minify()`
for `mangle` and `output` options.
By default `uglify-es` will not work around
Safari 10/11 bugs.
--self Build UglifyJS as a library (implies --wrap UglifyJS) --self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options: --source-map [options] Enable source map/specify source map options:
`base` Path to compute relative paths from input files. `base` Path to compute relative paths from input files.
@@ -509,8 +515,17 @@ if (result.error) throw result.error;
- `ie8` (default `false`) - set to `true` to support IE8. - `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 - `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
of function names. Useful for code relying on `Function.prototype.name`. of function names. Useful for code relying on `Function.prototype.name`. If the
top level minify option `keep_classnames` is `undefined` it will be overriden with
the value of the top level minify option `keep_fnames`.
- `safari10` (default: `false`) - pass `true` to work around Safari 10/11 bugs in
loop scoping and `await`. See `safari10` options in [`mangle`](#mangle-options)
and [`output`](#output-options) for details.
## Minify options structure ## Minify options structure
@@ -536,9 +551,12 @@ if (result.error) throw result.error;
// source map options // source map options
}, },
ecma: 5, // specify one of: 5, 6, 7 or 8 ecma: 5, // specify one of: 5, 6, 7 or 8
nameCache: null, // or specify a name cache object keep_classnames: false,
toplevel: false, keep_fnames: false,
ie8: false, ie8: false,
nameCache: null, // or specify a name cache object
safari10: false,
toplevel: false,
warnings: false, warnings: false,
} }
``` ```
@@ -609,17 +627,17 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
the resultant code is shorter: `m(){return x}` becomes `m:()=>x`. 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. 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 - `booleans` (default: `true`) -- various optimizations for boolean context,
? b : c → a ? b : c` for example `!!a ? b : c → a ? b : c`
- `cascade` (default: `true`) -- small optimization for sequences, transform `x, x` into `x` - `cascade` (default: `true`) -- small optimization for sequences, transform
and `x = something(), x` into `x = something()` `x, x` into `x` and `x = something(), x` into `x = something()`
- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables - side - `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables,
effects permitting. side effects permitting.
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes, for example: - `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary 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. nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `computed_props` (default: `true`) -- Transforms constant computed properties - `computed_props` (default: `true`) -- Transforms constant computed properties
@@ -630,7 +648,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `dead_code` (default: `true`) -- remove unreachable code - `dead_code` (default: `true`) -- remove unreachable code
- `drop_console` (default: `false`) -- default `false`. Pass `true` to discard calls to - `drop_console` (default: `false`) -- Pass `true` to discard calls to
`console.*` functions. If you wish to drop a specific function call `console.*` functions. If you wish to drop a specific function call
such as `console.info` and/or retain side effects from function arguments such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead. after dropping the function call then use `pure_funcs` instead.
@@ -642,14 +660,14 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions - `evaluate` (default: `true`) -- attempt to evaluate constant expressions
- `expression` (default: `false`) -- default `false`. Pass `true` to preserve completion values - `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets. from terminal statements without `return`, e.g. in bookmarklets.
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation) - `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_funs` (default: `true`) -- hoist function declarations - `hoist_funs` (default: `true`) -- hoist function declarations
- `hoist_props` (default: `false`) -- hoist properties from constant object and - `hoist_props` (default: `true`) -- hoist properties from constant object and
array literals into regular variables subject to a set of constraints. For example: 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` `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, works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
@@ -664,19 +682,22 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `join_vars` (default: `true`) -- join consecutive `var` statements - `join_vars` (default: `true`) -- join consecutive `var` statements
- `keep_fargs` (default: `true`) -- default `true`. Prevents the - `keep_classnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding unused function arguments. You need this compressor from discarding class names. See also: the `keep_classnames`
for code which relies on `Function.length`. [mangle option](#mangle).
- `keep_fargs` (default: `true`) -- Prevents the compressor from discarding unused
function arguments. You need this for code which relies on `Function.length`.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the - `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle). `Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from - `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome. being compressed into `1/0`, which may cause performance issues on Chrome.
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops when we can - `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
statically determine the condition when we can statically determine the condition.
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions" - `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the where the return value is discarded, to avoid the parens that the
@@ -707,11 +728,11 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
`foo` is certain to not throw, i.e. not `null` or `undefined`. `foo` is certain to not throw, i.e. not `null` or `undefined`.
- `reduce_funcs` (default: `true`) -- Allows single-use functions to be - `reduce_funcs` (default: `true`) -- Allows single-use functions to be
inlined as function expressions when permissible allowing further inlined as function expressions when permissible allowing further
optimization. Enabled by default. Option depends on `reduce_vars` optimization. Enabled by default. Option depends on `reduce_vars`
being enabled. Some code runs faster in the Chrome V8 engine if this being enabled. Some code runs faster in the Chrome V8 engine if this
option is disabled. Does not negatively impact other major browsers. option is disabled. Does not negatively impact other major browsers.
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and - `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
used as constant values. used as constant values.
@@ -724,21 +745,22 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
occasions the default sequences limit leads to very slow compress times in which occasions the default sequences limit leads to very slow compress times in which
case a value of `20` or less is recommended. case a value of `20` or less is recommended.
- `side_effects` (default: `true`) -- 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 functions marked as "pure". A function call is marked as "pure" if a comment
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();` example: `/*@__PURE__*/foo();`
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches - `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`) - `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
in the top level scope (`false` by default, `true` to drop both unreferenced variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
functions and variables) both unreferenced functions and variables)
- `top_retain` (default: `null`) -- prevent specific toplevel functions and variables from `unused` - `top_retain` (default: `null`) -- prevent specific toplevel functions and
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`) variables from `unused` removal (can be array, comma-separated, RegExp or
function. Implies `toplevel`)
- `typeofs` (default: `true`) -- default `true`. Transforms `typeof foo == "undefined"` into - `typeofs` (default: `true`) -- Transforms `typeof foo == "undefined"` into
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and `foo === void 0`. Note: recommend to set this value to `false` for IE10 and
earlier versions due to known issues. earlier versions due to known issues.
@@ -776,32 +798,34 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with - `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
`RegExp` values the same way as if they are constants. `RegExp` values the same way as if they are constants.
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple direct variable - `unused` (default: `true`) -- drop unreferenced functions and variables (simple
assignments do not count as references unless set to `"keep_assign"`) direct variable assignments do not count as references unless set to `"keep_assign"`)
- `warnings` (default: `false`) -- display warnings when dropping unreachable code or unused - `warnings` (default: `false`) -- display warnings when dropping unreachable
declarations etc. code or unused declarations etc.
## Mangle options ## Mangle options
- `eval` (default `false`). Pass `true` to mangle names visible in scopes - `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
where `eval` or `with` are used. where `eval` or `with` are used.
- `keep_classnames` (default `false`). Pass `true` to not mangle class names. - `keep_classnames` (default `false`) -- Pass `true` to not mangle class names.
See also: the `keep_classnames` [compress option](#compress-options).
- `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` Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
[compress option](#compress-options). [compress option](#compress-options).
- `reserved` (default `[]`). Pass an array of identifiers that should be - `reserved` (default `[]`) -- Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`. excluded from mangling. Example: `["foo", "bar"]`.
- `toplevel` (default `false`). Pass `true` to mangle names declared in the - `toplevel` (default `false`) -- Pass `true` to mangle names declared in the
top level scope. top level scope.
- `safari10` (default `false`). Pass `true` to work around the Safari 10 loop - `safari10` (default `false`) -- Pass `true` to work around the Safari 10 loop
iterator [bug](https://bugs.webkit.org/show_bug.cgi?id=171041) iterator [bug](https://bugs.webkit.org/show_bug.cgi?id=171041)
"Cannot declare a let variable twice". "Cannot declare a let variable twice".
See also: the `safari10` [output option](#output-options).
Examples: Examples:
@@ -901,6 +925,10 @@ can pass additional arguments that control the code output:
- `2` -- always use double quotes - `2` -- always use double quotes
- `3` -- always use the original quotes - `3` -- always use the original quotes
- `safari10` (default `false`) -- set this option to `true` to work around
the [Safari 10/11 await bug](https://bugs.webkit.org/show_bug.cgi?id=176685).
See also: the `safari10` [mangle option](#mangle-options).
- `semicolons` (default `true`) -- separate statements with semicolons. If - `semicolons` (default `true`) -- separate statements with semicolons. If
you pass `false` then whenever possible we will use a newline instead of a 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 semicolon, leading to more readable output of uglified code (size before

View File

@@ -46,8 +46,11 @@ program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define")); program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("--ecma <version>", "Specify 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("--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("--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("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--safari10", "Support non-standard Safari 10.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)"); program.option("--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("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.") program.option("--timings", "Display operations run time on STDERR.")
@@ -66,11 +69,14 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
"compress", "compress",
"ie8", "ie8",
"mangle", "mangle",
"rename",
"safari10",
"sourceMap", "sourceMap",
"toplevel", "toplevel",
"wrap" "wrap"
].forEach(function(name) { ].forEach(function(name) {
if (name in program) { if (name in program) {
if (name == "rename" && program[name]) return;
options[name] = program[name]; options[name] = program[name];
} }
}); });
@@ -95,6 +101,9 @@ if (program.define) {
options.compress.global_defs[expr] = program.define[expr]; options.compress.global_defs[expr] = program.define[expr];
} }
} }
if (program.keepClassnames) {
options.keep_classnames = true;
}
if (program.keepFnames) { if (program.keepFnames) {
options.keep_fnames = true; options.keep_fnames = true;
} }

View File

@@ -313,9 +313,9 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
cname: "[integer/S] current index for mangling variables (used internally by the mangler)", cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
}, },
get_defun_scope: function () { get_defun_scope: function() {
var self = this; var self = this;
while (self.is_block_scope() && self.parent_scope) { while (self.is_block_scope()) {
self = self.parent_scope; self = self.parent_scope;
} }
return self; return self;
@@ -908,7 +908,7 @@ var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator asyn
$documentation: "An ES6 concise method inside an object or class" $documentation: "An ES6 concise method inside an object or class"
}, AST_ObjectProperty); }, AST_ObjectProperty);
var AST_Class = DEFNODE("Class", "name extends properties", { var AST_Class = DEFNODE("Class", "name extends properties inlined", {
$propdoc: { $propdoc: {
name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.", name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
extends: "[AST_Node]? optional parent class", extends: "[AST_Node]? optional parent class",
@@ -1203,24 +1203,6 @@ TreeWalker.prototype = {
} }
} }
}, },
in_boolean_context: function() {
var stack = this.stack;
var i = stack.length, self = stack[--i];
while (i > 0) {
var p = stack[--i];
if ((p instanceof AST_If && p.condition === self) ||
(p instanceof AST_Conditional && p.condition === self) ||
(p instanceof AST_DWLoop && p.condition === self) ||
(p instanceof AST_For && p.condition === self) ||
(p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
{
return true;
}
if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
return false;
self = p;
}
},
loopcontrol_target: function(node) { loopcontrol_target: function(node) {
var stack = this.stack; var stack = this.stack;
if (node.label) for (var i = stack.length; --i >= 0;) { if (node.label) for (var i = stack.length; --i >= 0;) {

File diff suppressed because it is too large Load Diff

View File

@@ -51,11 +51,14 @@ function minify(files, options) {
compress: {}, compress: {},
ecma: undefined, ecma: undefined,
ie8: false, ie8: false,
keep_classnames: undefined,
keep_fnames: false, keep_fnames: false,
mangle: {}, mangle: {},
nameCache: null, nameCache: null,
output: {}, output: {},
parse: {}, parse: {},
rename: undefined,
safari10: false,
sourceMap: false, sourceMap: false,
timings: false, timings: false,
toplevel: false, toplevel: false,
@@ -65,9 +68,17 @@ function minify(files, options) {
var timings = options.timings && { var timings = options.timings && {
start: Date.now() 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("ecma", options, [ "parse", "compress", "output" ]);
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]); set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_classnames", options, [ "compress", "mangle" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("safari10", options, [ "mangle", "output" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]); set_shorthand("warnings", options, [ "compress" ]);
var quoted_props; var quoted_props;
@@ -141,6 +152,11 @@ function minify(files, options) {
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }
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 (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel); if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope = Date.now(); if (timings) timings.scope = Date.now();
@@ -201,7 +217,8 @@ function minify(files, options) {
if (timings) { if (timings) {
timings.end = Date.now(); timings.end = Date.now();
result.timings = { result.timings = {
parse: 1e-3 * (timings.compress - timings.parse), parse: 1e-3 * (timings.rename - timings.parse),
rename: 1e-3 * (timings.compress - timings.rename),
compress: 1e-3 * (timings.scope - timings.compress), compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope), scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle), mangle: 1e-3 * (timings.properties - timings.mangle),

View File

@@ -68,6 +68,7 @@ function OutputStream(options) {
preserve_line : false, preserve_line : false,
quote_keys : false, quote_keys : false,
quote_style : 0, quote_style : 0,
safari10 : false,
semicolons : true, semicolons : true,
shebang : true, shebang : true,
shorthand : undefined, shorthand : undefined,
@@ -677,7 +678,8 @@ function OutputStream(options) {
PARENS(AST_Await, function(output){ PARENS(AST_Await, function(output){
var p = output.parent(); var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this; || p instanceof AST_Call && p.expression === this
|| output.option("safari10") && p instanceof AST_UnaryPrefix;
}); });
PARENS(AST_Sequence, function(output){ PARENS(AST_Sequence, function(output){

View File

@@ -104,7 +104,7 @@ function reserve_quoted_keys(ast, reserved) {
function addStrings(node, add) { function addStrings(node, add) {
node.walk(new TreeWalker(function(node) { node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {
addStrings(node.expressions[node.expressions.length - 1], add); addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) { } else if (node instanceof AST_String) {
add(node.value); add(node.value);
} else if (node instanceof AST_Conditional) { } else if (node instanceof AST_Conditional) {

View File

@@ -43,7 +43,7 @@
"use strict"; "use strict";
function SymbolDef(scope, index, orig) { function SymbolDef(scope, orig) {
this.name = orig.name; this.name = orig.name;
this.orig = [ orig ]; this.orig = [ orig ];
this.eliminated = 0; this.eliminated = 0;
@@ -54,7 +54,6 @@ function SymbolDef(scope, index, orig) {
this.export = false; this.export = false;
this.mangled_name = null; this.mangled_name = null;
this.undeclared = false; this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++; this.id = SymbolDef.next_id++;
}; };
@@ -184,11 +183,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// scope when we encounter the AST_Defun node (which is // scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit // instanceof AST_Scope) but we get to the symbol a bit
// later. // later.
var parent_lambda = defun.parent_scope; mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node), 1);
while (parent_lambda.is_block_scope()) {
parent_lambda = parent_lambda.parent_scope;
}
mark_export((node.scope = parent_lambda).def_function(node), 1);
} }
else if (node instanceof AST_SymbolClass) { else if (node instanceof AST_SymbolClass) {
mark_export(defun.def_variable(node), 1); mark_export(defun.def_variable(node), 1);
@@ -346,7 +341,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
if (globals.has(name)) { if (globals.has(name)) {
return globals.get(name); return globals.get(name);
} else { } else {
var g = new SymbolDef(this, globals.size(), node); var g = new SymbolDef(this, node);
g.undeclared = true; g.undeclared = true;
g.global = true; g.global = true;
globals.set(name, g); globals.set(name, g);
@@ -417,7 +412,7 @@ AST_Scope.DEFMETHOD("def_function", function(symbol){
AST_Scope.DEFMETHOD("def_variable", function(symbol){ AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def; var def;
if (!this.variables.has(symbol.name)) { 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); this.variables.set(symbol.name, def);
def.global = !this.parent_scope; def.global = !this.parent_scope;
} else { } else {
@@ -435,7 +430,7 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling. // 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 // we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in // from some parent scope that is referenced in this or in
@@ -487,7 +482,7 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global; return this.definition().global;
}); });
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
options = defaults(options, { options = defaults(options, {
eval : false, eval : false,
ie8 : false, ie8 : false,
@@ -497,15 +492,14 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
toplevel : false, toplevel : false,
}); });
if (!Array.isArray(options.reserved)) options.reserved = []; if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
push_uniq(options.reserved, "arguments");
return options; return options;
}); });
AST_Toplevel.DEFMETHOD("mangle_names", function(options){ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options); options = this._default_mangler_options(options);
// Never mangle arguments
options.reserved.push('arguments');
// We only need to mangle declaration nodes. Special logic wired // We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's // 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 // present (and for AST_SymbolRef-s it'll use the mangled name of
@@ -514,11 +508,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var to_mangle = []; var to_mangle = [];
if (options.cache) { if (options.cache) {
this.globals.each(function(symbol){ this.globals.each(collect);
if (options.reserved.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
});
} }
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
@@ -530,13 +520,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker return true; // don't descend again in TreeWalker
} }
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
var p = tw.parent(), a = []; node.variables.each(collect);
node.variables.each(function(symbol){
if (options.reserved.indexOf(symbol.name) < 0) {
a.push(symbol);
}
});
to_mangle.push.apply(to_mangle, a);
return; return;
} }
if (node instanceof AST_Label) { if (node instanceof AST_Label) {
@@ -561,6 +545,79 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (options.cache) { if (options.cache) {
options.cache.cname = this.cname; options.cache.cname = this.cname;
} }
function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
}
});
AST_Toplevel.DEFMETHOD("find_unique_prefix", function(options) {
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
var cache = options.cache && options.cache.props;
var prefixes = Object.create(null);
options.reserved.forEach(add_prefix);
this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
}));
var prefix, i = 0;
do {
prefix = create_name(i++);
} while (prefixes[prefix]);
return prefix;
function add_prefix(name) {
if (/[0-9]$/.test(name)) {
prefixes[name.replace(/[0-9]+$/, "")] = true;
}
}
function add_def(def) {
var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
add_prefix(name);
}
function create_name(num) {
var name = "";
do {
name += letters[num % letters.length];
num = Math.floor(num / letters.length);
} while (num);
return name;
}
});
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
options = this._default_mangler_options(options);
var prefix = this.find_unique_prefix(options);
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
}));
function rename(def) {
if (def.global || def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return;
var d = def.redefined();
def.name = d ? d.name : prefix + def.id;
def.orig.forEach(function(sym) {
sym.name = def.name;
});
def.references.forEach(function(sym) {
sym.name = def.name;
});
}
});
AST_Node.DEFMETHOD("tail_node", return_this);
AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
}); });
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
@@ -591,7 +648,7 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
skip_string(node.consequent); skip_string(node.consequent);
skip_string(node.alternative); skip_string(node.alternative);
} else if (node instanceof AST_Sequence) { } else if (node instanceof AST_Sequence) {
skip_string(node.expressions[node.expressions.length - 1]); skip_string(node.tail_node());
} }
} }
}); });

View File

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

View File

@@ -483,6 +483,7 @@ issue_485_crashing_1530: {
ecma: 6, ecma: 6,
evaluate: true, evaluate: true,
inline: true, inline: true,
side_effects: true,
} }
input: { input: {
(function(a) { (function(a) {
@@ -490,9 +491,7 @@ issue_485_crashing_1530: {
var b = 42; var b = 42;
})(this); })(this);
} }
expect: { expect: {}
this, void 0;
}
} }
issue_2084: { issue_2084: {

View File

@@ -293,3 +293,31 @@ async_arrow_iife_negate_iife: {
} }
expect_exact: "(async()=>{await fetch()})();(()=>{plain()})();" expect_exact: "(async()=>{await fetch()})();(()=>{plain()})();"
} }
issue_2344_1: {
beautify = {
safari10: false,
}
input: {
async () => {
+await x;
await y;
return await z;
};
}
expect_exact: "async()=>{+await x;await y;return await z};"
}
issue_2344_2: {
beautify = {
safari10: true,
}
input: {
async () => {
+await x;
await y;
return await z;
};
}
expect_exact: "async()=>{+(await x);await y;return await z};"
}

View File

@@ -705,7 +705,7 @@ collapse_vars_lvalues_drop_assign: {
function f2(x) { var z = x, a = ++z; return z += a; } function f2(x) { var z = x, a = ++z; return z += a; }
function f3(x) { var a = (x -= 3); return x + a; } function f3(x) { var a = (x -= 3); return x + a; }
function f4(x) { var a = (x -= 3); return x + a; } function f4(x) { var a = (x -= 3); return x + a; }
function f5(x) { e1(); var v = e2(), c = v = --x; return x - c; } function f5(x) { e1(), e2(); var c = --x; return x - c; }
function f6(x) { e1(), e2(); return --x - x; } function f6(x) { e1(), e2(); return --x - x; }
function f7(x) { e1(); return x - (e2() - x); } function f7(x) { e1(); return x - (e2() - x); }
function f8(x) { e1(); return x - (e2() - x); } function f8(x) { e1(); return x - (e2() - x); }
@@ -2112,7 +2112,8 @@ chained_3: {
} }
expect: { expect: {
console.log(function(a, b) { console.log(function(a, b) {
var c = 1, c = b; var c = 1;
c = b;
b++; b++;
return c; return c;
}(0, 2)); }(0, 2));
@@ -2180,7 +2181,7 @@ inner_lvalues: {
expect_stdout: true expect_stdout: true
} }
double_def: { double_def_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
unused: true, unused: true,
@@ -2190,8 +2191,23 @@ double_def: {
a(); a();
} }
expect: { expect: {
var a = x; var a;
(a = a && y)(); (a = (a = x) && y)();
}
}
double_def_2: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = x, a = a && y;
a();
}
expect: {
(x && y)();
} }
} }
@@ -2300,7 +2316,7 @@ lvalues_def: {
} }
expect: { expect: {
var a = 0, b = 1; var a = 0, b = 1;
var a = b++, b = +void 0; a = b++, b = +void 0;
a && a[a++]; a && a[a++];
console.log(a, b); console.log(a, b);
} }
@@ -2666,6 +2682,7 @@ issue_2250_2: {
issue_2298: { issue_2298: {
options = { options = {
collapse_vars: true, collapse_vars: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
@@ -3353,10 +3370,9 @@ issue_2437: {
var result = !!req.onreadystatechange; var result = !!req.onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {}); Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
return result; return result;
} } else {
else {
var req = new XMLHttpRequest(); var req = new XMLHttpRequest();
var detectFunc = function () { }; var detectFunc = function () {};
req.onreadystatechange = detectFunc; req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null; req.onreadystatechange = null;
@@ -3367,13 +3383,14 @@ issue_2437: {
} }
expect: { expect: {
!function() { !function() {
if (xhrDesc) if (xhrDesc) {
return result = !!(req = new XMLHttpRequest()).onreadystatechange, var result = !!(req = new XMLHttpRequest()).onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}), return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result; result;
var req = new XMLHttpRequest(), detectFunc = function() {}; }
req.onreadystatechange = detectFunc; var req, detectFunc = function() {};
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; (req = new XMLHttpRequest()).onreadystatechange = detectFunc;
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null; req.onreadystatechange = null;
}(); }();
} }
@@ -3824,6 +3841,7 @@ issue_2436_12: {
issue_2436_13: { issue_2436_13: {
options = { options = {
collapse_vars: true, collapse_vars: true,
passes: 2,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -3880,3 +3898,82 @@ issue_2436_14: {
} }
expect_stdout: true expect_stdout: true
} }
issue_2497: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function sample() {
if (true) {
for (var i = 0; i < 1; ++i) {
for (var k = 0; k < 1; ++k) {
var value = 1;
var x = value;
value = x ? x + 1 : 0;
}
}
} else {
for (var i = 0; i < 1; ++i) {
for (var k = 0; k < 1; ++k) {
var value = 1;
}
}
}
}
}
expect: {
function sample() {
if (true)
for (var i = 0; i < 1; ++i)
for (var k = 0; k < 1; ++k) {
value = 1;
value = value ? value + 1 : 0;
}
else
for (i = 0; i < 1; ++i)
for (k = 0; k < 1; ++k)
var value = 1;
}
}
}
issue_2506: {
options = {
collapse_vars: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
var c = 0;
function f0(bar) {
function f1(Infinity_2) {
function f13(NaN) {
if (false <= NaN & this >> 1 >= 0) {
c++;
}
}
var b_2 = f13(NaN, c++);
}
var bar = f1(-3, -1);
}
f0(false);
console.log(c);
}
expect: {
var c = 0;
function f0(bar) {
(function(Infinity_2) {
(function(NaN) {
if (false <= 0/0 & this >> 1 >= 0)
c++;
})(0, c++);
})();
}
f0(false);
console.log(c);
}
expect_stdout: "1"
}

View File

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

View File

@@ -129,8 +129,8 @@ dead_code_constant_boolean_should_warn_more: {
var bar; var bar;
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var x = 10, y;
var moo; var moo;
var x = 10, y;
bar(); bar();
} }
expect_stdout: true expect_stdout: true
@@ -165,8 +165,8 @@ dead_code_constant_boolean_should_warn_more_strict: {
var foo; var foo;
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var x = 10, y;
var moo; var moo;
var x = 10, y;
bar(); bar();
} }
expect_stdout: true expect_stdout: true
@@ -175,10 +175,11 @@ dead_code_constant_boolean_should_warn_more_strict: {
dead_code_block_decls_die: { dead_code_block_decls_die: {
options = { options = {
dead_code : true, booleans: true,
conditionals : true, conditionals: true,
booleans : true, dead_code: true,
evaluate : true evaluate: true,
side_effects: true,
}; };
input: { input: {
if (0) { if (0) {
@@ -197,13 +198,14 @@ dead_code_block_decls_die: {
dead_code_const_declaration: { dead_code_const_declaration: {
options = { options = {
dead_code : true, booleans: true,
loops : true, conditionals: true,
booleans : true, dead_code: true,
conditionals : true, evaluate: true,
evaluate : true, loops: true,
reduce_funcs : true, reduce_funcs: true,
reduce_vars : true, reduce_vars: true,
side_effects: true,
}; };
input: { input: {
var unused; var unused;
@@ -225,14 +227,15 @@ dead_code_const_declaration: {
dead_code_const_annotation: { dead_code_const_annotation: {
options = { options = {
dead_code : true, booleans: true,
loops : true, conditionals: true,
booleans : true, dead_code: true,
conditionals : true, evaluate: true,
evaluate : true, loops: true,
reduce_funcs : true, reduce_funcs: true,
reduce_vars : true, reduce_vars: true,
toplevel : true, side_effects: true,
toplevel: true,
}; };
input: { input: {
var unused; var unused;
@@ -278,14 +281,16 @@ dead_code_const_annotation_regex: {
dead_code_const_annotation_complex_scope: { dead_code_const_annotation_complex_scope: {
options = { options = {
dead_code : true, booleans: true,
loops : true, conditionals: true,
booleans : true, dead_code: true,
conditionals : true, evaluate: true,
evaluate : true, loops: true,
reduce_funcs : true, reduce_funcs: true,
reduce_vars : true, reduce_vars: true,
toplevel : true, sequences: true,
side_effects: true,
toplevel: true,
}; };
input: { input: {
var unused_var; var unused_var;
@@ -328,6 +333,8 @@ try_catch_finally: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
passes: 2,
side_effects: true,
} }
input: { input: {
var a = 1; var a = 1;
@@ -571,6 +578,7 @@ issue_2383_1: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
side_effects: true,
} }
input: { input: {
if (0) { if (0) {
@@ -587,6 +595,7 @@ issue_2383_2: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
side_effects: true,
} }
input: { input: {
if (0) { if (0) {
@@ -610,6 +619,7 @@ issue_2383_3: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
side_effects: true,
} }
input: { input: {
var b = 7, y = 8; var b = 7, y = 8;

View File

@@ -260,7 +260,9 @@ keep_fnames: {
} }
drop_assign: { drop_assign: {
options = { unused: true }; options = {
unused: true,
}
input: { input: {
function f1() { function f1() {
var a; var a;
@@ -281,7 +283,7 @@ drop_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
} };
} }
} }
expect: { expect: {
@@ -298,16 +300,17 @@ drop_assign: {
return 1; return 1;
} }
function f5() { function f5() {
var a;
return function() { return function() {
a = 1; 1;
} };
} }
} }
} }
keep_assign: { keep_assign: {
options = { unused: "keep_assign" }; options = {
unused: "keep_assign",
}
input: { input: {
function f1() { function f1() {
var a; var a;
@@ -328,7 +331,7 @@ keep_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
} };
} }
} }
expect: { expect: {
@@ -351,19 +354,22 @@ keep_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
} };
} }
} }
} }
drop_toplevel_funcs: { drop_toplevel_funcs: {
options = { toplevel: "funcs", unused: true }; options = {
toplevel: "funcs",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -379,13 +385,16 @@ drop_toplevel_funcs: {
} }
drop_toplevel_vars: { drop_toplevel_vars: {
options = { toplevel: "vars", unused: true }; options = {
toplevel: "vars",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -393,11 +402,10 @@ drop_toplevel_vars: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
2; 2;
function g() {} function g() {}
@@ -407,13 +415,17 @@ drop_toplevel_vars: {
} }
drop_toplevel_vars_fargs: { drop_toplevel_vars_fargs: {
options = { keep_fargs: false, toplevel: "vars", unused: true }; options = {
keep_fargs: false,
toplevel: "vars",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -421,11 +433,10 @@ drop_toplevel_vars_fargs: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var c = g;
function f() { function f() {
return function() { return function() {
c = 2; 2;
} };
} }
2; 2;
function g() {} function g() {}
@@ -435,13 +446,16 @@ drop_toplevel_vars_fargs: {
} }
drop_toplevel_all: { drop_toplevel_all: {
options = { toplevel: true, unused: true }; options = {
toplevel: true,
unused: true
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -455,13 +469,16 @@ drop_toplevel_all: {
} }
drop_toplevel_retain: { drop_toplevel_retain: {
options = { top_retain: "f,a,o", unused: true }; options = {
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -469,26 +486,28 @@ drop_toplevel_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a, c = g; var a;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_retain_array: { drop_toplevel_retain_array: {
options = { top_retain: [ "f", "a", "o" ], unused: true }; options = {
top_retain: [ "f", "a", "o" ],
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -496,26 +515,28 @@ drop_toplevel_retain_array: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a, c = g; var a;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_retain_regex: { drop_toplevel_retain_regex: {
options = { top_retain: /^[fao]$/, unused: true }; options = {
top_retain: /^[fao]$/,
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -523,26 +544,29 @@ drop_toplevel_retain_regex: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a, c = g; var a;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_all_retain: { drop_toplevel_all_retain: {
options = { toplevel: true, top_retain: "f,a,o", unused: true }; options = {
toplevel: true,
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -550,26 +574,29 @@ drop_toplevel_all_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a, c = g; var a;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_funcs_retain: { drop_toplevel_funcs_retain: {
options = { toplevel: "funcs", top_retain: "f,a,o", unused: true }; options = {
toplevel: "funcs",
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -581,7 +608,7 @@ drop_toplevel_funcs_retain: {
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -590,13 +617,17 @@ drop_toplevel_funcs_retain: {
} }
drop_toplevel_vars_retain: { drop_toplevel_vars_retain: {
options = { toplevel: "vars", top_retain: "f,a,o", unused: true }; options = {
toplevel: "vars",
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -604,11 +635,11 @@ drop_toplevel_vars_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a, c = g; var a;
function f(d) { function f(d) {
return function() { return function() {
c = 2; 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -618,13 +649,16 @@ drop_toplevel_vars_retain: {
} }
drop_toplevel_keep_assign: { drop_toplevel_keep_assign: {
options = { toplevel: true, unused: "keep_assign" }; options = {
toplevel: true,
unused: "keep_assign",
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
} };
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -866,11 +900,11 @@ issue_1583: {
expect: { expect: {
function m(t) { function m(t) {
(function(e) { (function(e) {
t = function() { (function() {
return (function(a) { return (function(a) {
return function(a) {}; return function(a) {};
})(); })();
}(); })();
})(); })();
} }
} }
@@ -1569,8 +1603,186 @@ issue_2288: {
expect: { expect: {
function foo(o) { function foo(o) {
o.a; o.a;
for (i = 0; i < 0; i++);
for (var i = 0; i < 0; i++); for (var i = 0; i < 0; i++);
for (i = 0; i < 0; i++);
} }
} }
} }
issue_2516_1: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function foo() {
function qux(x) {
bar.call(null, x);
}
function bar(x) {
var FOUR = 4;
var trouble = x || never_called();
var value = (FOUR - 1) * trouble;
console.log(value == 6 ? "PASS" : value);
}
Baz = qux;
}
var Baz;
foo();
Baz(2);
}
expect: {
function foo() {
Baz = function(x) {
(function(x) {
var trouble = x || never_called();
var value = (4 - 1) * trouble;
console.log(6 == value ? "PASS" : value);
}).call(null, x);
};
}
var Baz;
foo();
Baz(2);
}
}
issue_2516_2: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
passes: 2,
unused: true,
}
input: {
function foo() {
function qux(x) {
bar.call(null, x);
}
function bar(x) {
var FOUR = 4;
var trouble = x || never_called();
var value = (FOUR - 1) * trouble;
console.log(value == 6 ? "PASS" : value);
}
Baz = qux;
}
var Baz;
foo();
Baz(2);
}
expect: {
function foo() {
Baz = function(x) {
(function(x) {
var value = (4 - 1) * (x || never_called());
console.log(6 == value ? "PASS" : value);
}).call(null, x);
};
}
var Baz;
foo();
Baz(2);
}
}
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

@@ -1,6 +1,7 @@
and: { and: {
options = { options = {
evaluate: true evaluate: true,
side_effects: true,
} }
input: { input: {
var a; var a;
@@ -76,7 +77,8 @@ and: {
or: { or: {
options = { options = {
evaluate: true evaluate: true,
side_effects: true,
} }
input: { input: {
var a; var a;
@@ -158,7 +160,8 @@ or: {
unary_prefix: { unary_prefix: {
options = { options = {
evaluate: true evaluate: true,
side_effects: true,
} }
input: { input: {
a = !0 && b; a = !0 && b;
@@ -1338,3 +1341,95 @@ self_comparison_2: {
} }
expect_stdout: "false false true true 'number'" expect_stdout: "false false true true 'number'"
} }
issue_2535_1: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
if ((x() || true) || y()) z();
if ((x() || true) && y()) z();
if ((x() && true) || y()) z();
if ((x() && true) && y()) z();
if ((x() || false) || y()) z();
if ((x() || false) && y()) z();
if ((x() && false) || y()) z();
if ((x() && false) && y()) z();
}
expect: {
if (x(), 1) z();
if (x(), y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x(), y()) z();
if (x(), 0) z();
}
}
issue_2535_2: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
(x() || true) || y();
(x() || true) && y();
(x() && true) || y();
(x() && true) && y();
(x() || false) || y();
(x() || false) && y();
(x() && false) || y();
(x() && false) && y();
}
expect: {
x(),
x(), y(),
x() || y(),
x() && y(),
x() || y(),
x() && y(),
x(), y(),
x();
}
}
issue_2535_3: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(Object(1) && 1 && 2);
console.log(Object(1) && true && 1 && 2 && Object(2));
console.log(Object(1) && true && 1 && null && 2 && Object(2));
console.log(2 == Object(1) || 0 || void 0 || null);
console.log(2 == Object(1) || 0 || void 0 || null || Object(2));
console.log(2 == Object(1) || 0 || void 0 || "ok" || null || Object(2));
}
expect: {
console.log(Object(1) && 2);
console.log(Object(1) && Object(2));
console.log(Object(1) && null);
console.log(2 == Object(1) || null);
console.log(2 == Object(1) || Object(2));
console.log(2 == Object(1) || "ok");
}
expect_stdout: true
expect_warnings: [
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1409,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1410,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1411,20]",
"WARN: Condition left of && always false [test/compress/evaluate.js:1411,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1412,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1413,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1414,20]",
"WARN: Condition left of || always true [test/compress/evaluate.js:1414,20]",
]
}

View File

@@ -36,19 +36,19 @@ avoid_spread_in_ternary: {
function print(...x) { function print(...x) {
console.log(...x); console.log(...x);
} }
var a = [1, 2], b = [3, 4]; var a = [1, 2], b = [3, 4], m = Math;
if (Math) if (m)
print(a); print(a);
else else
print(b); print(b);
if (Math) if (m)
print(...a); print(...a);
else else
print(b); print(b);
if (Math.no_such_property) if (m.no_such_property)
print(a); print(a);
else else
print(...b); print(...b);
@@ -57,10 +57,10 @@ avoid_spread_in_ternary: {
function print(...x) { function print(...x) {
console.log(...x); console.log(...x);
} }
var a = [ 1, 2 ], b = [ 3, 4 ]; var a = [ 1, 2 ], b = [ 3, 4 ], m = Math;
print(Math ? a : b); print(m ? a : b);
Math ? print(...a) : print(b); m ? print(...a) : print(b);
Math.no_such_property ? print(a) : print(...b); m.no_such_property ? print(a) : print(...b);
} }
expect_stdout: [ expect_stdout: [
"[ 1, 2 ]", "[ 1, 2 ]",

View File

@@ -87,6 +87,7 @@ issue_485_crashing_1530: {
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
inline: true, inline: true,
side_effects: true,
} }
input: { input: {
(function(a) { (function(a) {
@@ -94,9 +95,7 @@ issue_485_crashing_1530: {
var b = 42; var b = 42;
})(this); })(this);
} }
expect: { expect: {}
this, void 0;
}
} }
issue_1841_1: { issue_1841_1: {
@@ -554,3 +553,122 @@ issue_2428: {
"PASS", "PASS",
] ]
} }
issue_2531_1: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function outer() {
function inner(value) {
function closure() {
return value;
}
return function() {
return closure();
};
}
return inner("Hello");
}
console.log("Greeting:", outer()());
}
expect: {
function outer() {
return function(value) {
return function() {
return value;
};
}("Hello");
}
console.log("Greeting:", outer()());
}
expect_stdout: "Greeting: Hello"
}
issue_2531_2: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function outer() {
function inner(value) {
function closure() {
return value;
}
return function() {
return closure();
};
}
return inner("Hello");
}
console.log("Greeting:", outer()());
}
expect: {
function outer() {
return function() {
return "Hello";
};
}
console.log("Greeting:", outer()());
}
expect_stdout: "Greeting: Hello"
}
issue_2531_3: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function outer() {
function inner(value) {
function closure() {
return value;
}
return function() {
return closure();
};
}
return inner("Hello");
}
console.log("Greeting:", outer()());
}
expect: {
console.log("Greeting:", "Hello");
}
expect_stdout: "Greeting: Hello"
}
empty_body: {
options = {
reduce_vars: true,
side_effects: true,
}
input: {
function f() {
function noop() {}
noop();
return noop;
}
}
expect: {
function f() {
function noop() {}
return noop;
}
}
}

View File

@@ -184,6 +184,7 @@ issue_2167: {
global_defs: { global_defs: {
"@isDevMode": "function(){}", "@isDevMode": "function(){}",
}, },
passes: 2,
side_effects: true, side_effects: true,
} }
input: { input: {

View File

@@ -13,7 +13,8 @@ arrow_function_parens_2: {
typeof_arrow_functions: { typeof_arrow_functions: {
options = { options = {
evaluate: true evaluate: true,
typeofs: true,
} }
input: { input: {
var foo = typeof (x => null); var foo = typeof (x => null);
@@ -975,3 +976,180 @@ shorthand_keywords: {
expect_stdout: true expect_stdout: true
node_version: ">=4" 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

@@ -389,6 +389,7 @@ hoist_class: {
evaluate: true, evaluate: true,
hoist_props: true, hoist_props: true,
inline: true, inline: true,
keep_classnames: true,
keep_fnames: true, keep_fnames: true,
passes: 2, passes: 2,
reduce_funcs: true, reduce_funcs: true,
@@ -432,6 +433,7 @@ hoist_class_with_new: {
evaluate: true, evaluate: true,
hoist_props: true, hoist_props: true,
inline: true, inline: true,
keep_classnames: true,
keep_fnames: true, keep_fnames: true,
passes: 2, passes: 2,
reduce_funcs: true, reduce_funcs: true,
@@ -452,17 +454,12 @@ hoist_class_with_new: {
console.log(o.p.name, o.p === o.p, new o.p(o.x).value, new o.p(o.y).value); console.log(o.p.name, o.p === o.p, new o.p(o.x).value, new o.p(o.y).value);
} }
expect: { expect: {
// FIXME: class `o.p` not hoisted due to `new` var o_p = class Foo {
var o = { constructor(value) {
p: class Foo { this.value = 10 * value;
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); console.log(o_p.name, true, new o_p(1).value, new o_p(2).value);
} }
node_version: ">=6" node_version: ">=6"
expect_stdout: "Foo true 10 20" expect_stdout: "Foo true 10 20"
@@ -637,3 +634,192 @@ issue_2473_4: {
} }
expect_stdout: "1 2" expect_stdout: "1 2"
} }
issue_2508_1: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ 1 ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})([ 1 ]);
}
expect_stdout: true
}
issue_2508_2: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: 2 },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})({ b: 2 });
}
expect_stdout: true
}
issue_2508_3: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_4: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_5: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: function(x) {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = function(x) {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2508_6: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: x => {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = x => {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2519: {
options = {
collapse_vars: true,
evaluate: true,
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
function testFunc() {
var dimensions = {
minX: 5,
maxX: 6,
};
var scale = 1;
var d = {
x: (dimensions.maxX + dimensions.minX) / 2,
};
return d.x * scale;
}
console.log(testFunc());
}
expect: {
function testFunc() {
return 1 * ((6 + 5) / 2);
}
console.log(testFunc());
}
expect_stdout: "5.5"
}

View File

@@ -26,7 +26,7 @@ issue_1639_1: {
} }
expect: { expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;) for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, !1) var ignore = 0; if (--b, 0) var ignore = 0;
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: true
@@ -57,7 +57,7 @@ issue_1639_2: {
expect: { expect: {
var a = 100, b = 10; var a = 100, b = 10;
function f19() { function f19() {
++a, 1; ++a, 0;
} }
f19(), f19(),
console.log(a, b); console.log(a, b);

View File

@@ -39,7 +39,7 @@ f7: {
"var b = 10;", "var b = 10;",
"", "",
"!function() {", "!function() {",
" for (;b = 100, !1; ) ;", " b = 100;",
"}(), console.log(100, b);", "}(), console.log(100, b);",
] ]
expect_stdout: true expect_stdout: true

View File

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

View File

@@ -134,5 +134,5 @@ label_while: {
L: while (0) continue L; L: while (0) continue L;
} }
} }
expect_exact: "function f(){L:;}" expect_exact: "function f(){L:0}"
} }

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
this_binding_conditionals: { this_binding_conditionals: {
options = { options = {
conditionals: true, conditionals: true,
evaluate : true evaluate: true,
side_effects: true,
}; };
input: { input: {
(1 && a)(); (1 && a)();

View File

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

View File

@@ -812,3 +812,204 @@ prop_arrow_with_nested_this: {
] ]
node_version: ">=4" node_version: ">=4"
} }
issue_2554_1: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var obj = {
["x" + ""]: 1,
["method" + ""]() {
this.s = "PASS";
},
get ["g" + ""]() {
return this.x;
},
set ["s" + ""](value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect: {
var obj = {
x: 1,
method() {
this.s = "PASS";
},
get g() {
return this.x;
},
set s(value) {
this.x = value;
}
};
obj.method();
console.log(obj.g);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_2: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var instance = new class {
constructor() {
this.x = 2;
}
["method" + ""]() {
this.s = "PASS";
}
get ["g" + ""]() {
return this.x;
}
set ["s" + ""](value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect: {
var instance = new class {
constructor() {
this.x = 2;
}
method() {
this.s = "PASS";
}
get g() {
return this.x;
}
set s(value) {
this.x = value;
}
}();
instance.method();
console.log(instance.g);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_3: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var foo = {
[1 + 0]: 1,
[2 + 0]() {
this[4] = "PASS";
},
get [3 + 0]() {
return this[1];
},
set [4 + 0](value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect: {
var foo = {
1: 1,
2() {
this[4] = "PASS";
},
get 3() {
return this[1];
},
set 4(value) {
this[1] = value;
}
};
foo[2]();
console.log(foo[3]);
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_2554_4: {
options = {
computed_props: true,
evaluate: true,
}
input: {
var bar = new class {
constructor() {
this[1] = 2;
}
[2 + 0]() {
this[4] = "PASS";
}
get [3 + 0]() {
return this[1];
}
set [4 + 0](value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect: {
var bar = new class {
constructor() {
this[1] = 2;
}
2() {
this[4] = "PASS";
}
get 3() {
return this[1];
}
set 4(value) {
this[1] = value;
}
}();
bar[2]();
console.log(bar[3]);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2554_5: {
options = {
computed_props: true,
evaluate: true,
}
input: {
new class {
["constructor"]() {
console.log("FAIL");
}
"constructor"() {
console.log("PASS");
}
}();
}
expect: {
new class {
["constructor"]() {
console.log("FAIL");
}
constructor() {
console.log("PASS");
}
}();
}
expect_stdout: "PASS"
node_version: ">=6"
}

View File

@@ -1305,3 +1305,29 @@ new_this: {
}(42); }(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

@@ -972,8 +972,8 @@ inner_var_for_2: {
} }
expect: { expect: {
!function() { !function() {
a = 1; var a = 1;
for (var b = 1; --b;) var a = 2; for (var b = 1; --b;) a = 2;
console.log(a); console.log(a);
}(); }();
} }
@@ -1209,6 +1209,7 @@ toplevel_on_loops_2: {
loops: true, loops: true,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true,
toplevel:true, toplevel:true,
unused: true, unused: true,
} }
@@ -2346,7 +2347,7 @@ booleans: {
} }
expect: { expect: {
console.log(function(a) { console.log(function(a) {
if (!1); if (0);
switch (!1) { switch (!1) {
case 0: case 0:
return "FAIL"; return "FAIL";
@@ -4819,3 +4820,459 @@ issue_2485: {
} }
expect_stdout: "6" expect_stdout: "6"
} }
issue_2496: {
options = {
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function execute(callback) {
callback();
}
class Foo {
constructor(message) {
this.message = message;
}
go() {
this.message = "PASS";
console.log(this.message);
}
run() {
execute(() => {
this.go();
});
}
}
new Foo("FAIL").run();
}
expect: {
new class {
constructor(message) {
this.message = message;
}
go() {
this.message = "PASS";
console.log(this.message);
}
run() {
(function(callback) {
callback();
})(() => {
this.go();
});
}
}("FAIL").run();
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_2416: {
options = {
keep_classnames: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
class Foo {}
console.log(Foo.name);
}
expect: {
console.log((class Foo {}).name);
}
expect_stdout: "Foo"
node_version: ">=6"
}
issue_2455: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function foo() {
var that = this;
for (;;) that.bar();
}
}
expect: {
function foo() {
for (;;) this.bar();
}
}
}
issue_2560_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz(s) {
return s ? foo : bar;
}
function foo() {}
function bar() {}
main();
}
expect: {
function baz(s) {
return s ? foo : bar;
}
function foo() {}
function bar() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz() {
return foo, bar;
}
function foo() {}
function bar() {}
main();
}
expect: {
function baz() {
return function() {}, bar;
}
function bar() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_3: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function baz() {
try {
throw foo;
} catch (bar) {
return bar;
}
}
function foo() {}
main();
}
expect: {
function baz() {
try {
throw foo;
} catch (bar) {
return bar;
}
}
function foo() {}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_2560_4: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz(s) {
function foo() {}
function bar() {}
return s ? foo : bar;
}
main();
}
expect: {
function baz(s) {
return s ? function() {} : function() {};
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
issue_2560_5: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz() {
function foo() {}
function bar() {}
return foo, bar;
}
main();
}
expect: {
function baz() {
return function() {}, function() {};
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
issue_2560_6: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
}
function baz() {
function foo() {}
try {
throw foo;
} catch (bar) {
return bar;
}
}
main();
}
expect: {
function baz() {
// TODO: improve to match `master`
function foo() {}
try {
throw foo;
} catch (bar) {
return bar;
}
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("PASS");
else
console.log("FAIL");
})();
}
expect_stdout: "PASS"
}
escape_yield: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = gen.next().value;
if (thing !== (thing = gen.next().value))
console.log("FAIL");
else
console.log("PASS");
}
function foo() {}
function* baz(s) {
for (;;) yield foo;
}
var gen = baz();
main();
}
expect: {
function foo() {}
var gen = function*(s) {
for (;;) yield foo;
}();
(function() {
var thing = gen.next().value;
if (thing !== (thing = gen.next().value))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=4"
}
escape_await: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing;
baz().then(x => {
thing = x;
});
baz().then(x => {
if (thing !== (thing = x))
console.log("FAIL");
else
console.log("PASS");
});
}
function foo() {}
async function baz() {
return await foo;
}
main();
}
expect: {
function foo() {}
async function baz() {
return await foo;
}
(function() {
var thing;
baz().then(x => {
thing = x;
});
baz().then(x => {
if (thing !== (thing = x))
console.log("FAIL");
else
console.log("PASS");
});
})();
}
}
escape_expansion: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function main() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
}
function foo() {}
function bar(...x) {
return x[0];
}
function baz() {
return bar(...[ foo ]);
}
main();
}
expect: {
function foo() {}
function baz() {
return function(...x) {
return x[0];
}(...[ foo ]);
}
(function() {
var thing = baz();
if (thing !== (thing = baz()))
console.log("FAIL");
else
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=6"
}

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

@@ -122,3 +122,25 @@ return_undefined: {
} }
} }
} }
return_void: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g() {
h();
}
return g();
}
}
expect: {
function f() {
h();
}
}
}

View File

@@ -252,13 +252,12 @@ negate_iife_for: {
input: { input: {
(function() {})(); (function() {})();
for (i = 0; i < 5; i++) console.log(i); for (i = 0; i < 5; i++) console.log(i);
(function() {})(); (function() {})();
for (; i < 5; i++) console.log(i); for (; i < 10; i++) console.log(i);
} }
expect: { expect: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i); for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 5; i++) console.log(i); for (!function() {}(); i < 10; i++) console.log(i);
} }
expect_stdout: true expect_stdout: true
} }

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ describe("bin/uglifyjs", function () {
command += semver.satisfies(process.version, ">=4") ? "6" : "5"; command += semver.satisfies(process.version, ">=4") ? "6" : "5";
command += ',passes=3,keep_fargs=false,unsafe --wrap WrappedUglifyJS'; command += ',passes=3,keep_fargs=false,unsafe --wrap WrappedUglifyJS';
exec(command, function (err, stdout) { exec(command, { maxBuffer: 1048576 }, function (err, stdout) {
if (err) throw err; if (err) throw err;
eval(stdout); eval(stdout);

View File

@@ -354,7 +354,8 @@ describe("minify", function() {
Uglify.minify(ast, { Uglify.minify(ast, {
compress: { compress: {
sequences: false sequences: false
} },
mangle: false
}); });
assert.ok(stat.body); assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()"); assert.strictEqual(stat.print_to_string(), "a=x()");

View File

@@ -10,7 +10,7 @@ describe("spidermonkey export/import sanity test", function() {
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " + var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
uglifyjs + " -p spidermonkey -cm"; uglifyjs + " -p spidermonkey -cm";
exec(command, function(err, stdout) { exec(command, { maxBuffer: 1048576 }, function(err, stdout) {
if (err) throw err; if (err) throw err;
eval(stdout); eval(stdout);

View File

@@ -117,6 +117,10 @@ function run_compress_tests() {
test.mangle.properties.reserved = quoted_props; test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, 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 cmp = new U.Compressor(options, true);
var output = cmp.compress(input); var output = cmp.compress(input);
output.figure_out_scope(test.mangle); output.figure_out_scope(test.mangle);