Compare commits
57 Commits
harmony-v3
...
v3.1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fd927a7cc | ||
|
|
8428326ea1 | ||
|
|
31f8209193 | ||
|
|
9b0f86f5a1 | ||
|
|
ee082ace1b | ||
|
|
ae67a49850 | ||
|
|
4178289c38 | ||
|
|
74ae16f9f8 | ||
|
|
1968203d83 | ||
|
|
86ea38a259 | ||
|
|
8a713e449f | ||
|
|
24aa07855b | ||
|
|
5fd723f143 | ||
|
|
516eaef50c | ||
|
|
4ae1fb3ed8 | ||
|
|
011123223b | ||
|
|
96439ca246 | ||
|
|
c927cea632 | ||
|
|
9f4b98f8e4 | ||
|
|
0f2ef3367c | ||
|
|
7e5b5cac97 | ||
|
|
c1346e06b7 | ||
|
|
0d2fe8e3ef | ||
|
|
f2b9c11e2a | ||
|
|
fe647b083e | ||
|
|
dfe4f6c6de | ||
|
|
a09c8ad666 | ||
|
|
ec598c351b | ||
|
|
eba0f93bc0 | ||
|
|
99800d4aa9 | ||
|
|
70d56c951a | ||
|
|
b810e2f8da | ||
|
|
1abe14296e | ||
|
|
6920e898d1 | ||
|
|
dd71639264 | ||
|
|
2dcc552ce0 | ||
|
|
55387e8fd0 | ||
|
|
7e3e9da860 | ||
|
|
00f509405b | ||
|
|
aceb0af36b | ||
|
|
4f0953f7e9 | ||
|
|
182a47bfb1 | ||
|
|
cd27f4ec38 | ||
|
|
8158b1bdcf | ||
|
|
aacf3edc68 | ||
|
|
8b89072190 | ||
|
|
395a17ccda | ||
|
|
3f355866cf | ||
|
|
71d52f147d | ||
|
|
eb7adaa6fc | ||
|
|
e5cf7972ea | ||
|
|
f81ff10a9b | ||
|
|
16d40915b4 | ||
|
|
e7c21e87e3 | ||
|
|
c4c2ef44d0 | ||
|
|
a845897758 | ||
|
|
32ea2c5530 |
9
.github/ISSUE_TEMPLATE.md
vendored
9
.github/ISSUE_TEMPLATE.md
vendored
@@ -8,7 +8,14 @@
|
|||||||
|
|
||||||
**Uglify version (`uglifyjs -V`)**
|
**Uglify version (`uglifyjs -V`)**
|
||||||
|
|
||||||
**JavaScript input** <!-- ideally as small as possible -->
|
**JavaScript input**
|
||||||
|
|
||||||
|
<!--
|
||||||
|
A complete parsable JS program exhibiting the issue with
|
||||||
|
UglifyJS alone - without third party tools or libraries.
|
||||||
|
Ideally the input should be as small as possible.
|
||||||
|
Post a link to a gist if necessary.
|
||||||
|
-->
|
||||||
|
|
||||||
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
||||||
|
|
||||||
|
|||||||
287
README.md
287
README.md
@@ -150,19 +150,19 @@ debugging your compressed JavaScript. To get a source map, pass
|
|||||||
|
|
||||||
Additional options:
|
Additional options:
|
||||||
|
|
||||||
- `--source-map filename=<NAME>` to specify the name of the source map.
|
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
|
||||||
|
|
||||||
- `--source-map root=<URL>` to pass the URL where the original files can be found.
|
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
||||||
|
|
||||||
|
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
|
||||||
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
||||||
`//# sourceMappingURL=` directive.
|
`//# sourceMappingURL=` directive.
|
||||||
|
|
||||||
- `--source-map url=<URL>` to specify the URL where the source map can be found.
|
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
uglifyjs js/file1.js js/file2.js \
|
uglifyjs js/file1.js js/file2.js \
|
||||||
-o foo.min.js -c -m \
|
-o foo.min.js -c -m \
|
||||||
--source-map root="http://foo.com/src",url=foo.min.js.map
|
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
|
||||||
|
|
||||||
The above will compress and mangle `file1.js` and `file2.js`, will drop the
|
The above will compress and mangle `file1.js` and `file2.js`, will drop the
|
||||||
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
|
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
|
||||||
@@ -181,8 +181,8 @@ CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →
|
|||||||
compressed JS by mapping every token in the compiled JS to its original
|
compressed JS by mapping every token in the compiled JS to its original
|
||||||
location.
|
location.
|
||||||
|
|
||||||
To use this feature pass `--source-map content="/path/to/input/source.map"`
|
To use this feature pass `--source-map "content='/path/to/input/source.map'"`
|
||||||
or `--source-map content=inline` if the source map is included inline with
|
or `--source-map "content=inline"` if the source map is included inline with
|
||||||
the sources.
|
the sources.
|
||||||
|
|
||||||
## CLI compress options
|
## CLI compress options
|
||||||
@@ -203,17 +203,15 @@ Example:
|
|||||||
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
||||||
(comma-separated) options are supported:
|
(comma-separated) options are supported:
|
||||||
|
|
||||||
- `toplevel` — mangle names declared in the top level scope (disabled by
|
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
|
||||||
default).
|
|
||||||
|
|
||||||
- `eval` — mangle names visible in scopes where `eval` or `with` are used
|
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
|
||||||
(disabled by default).
|
|
||||||
|
|
||||||
When mangling is enabled but you want to prevent certain names from being
|
When mangling is enabled but you want to prevent certain names from being
|
||||||
mangled, you can declare those names with `--mangle reserved` — pass a
|
mangled, you can declare those names with `--mangle reserved` — pass a
|
||||||
comma-separated list of names. For example:
|
comma-separated list of names. For example:
|
||||||
|
|
||||||
uglifyjs ... -m reserved=[$,require,exports]
|
uglifyjs ... -m reserved=['$','require','exports']
|
||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
@@ -223,7 +221,7 @@ to prevent the `require`, `exports` and `$` names from being changed.
|
|||||||
is a separate step, different from variable name mangling. Pass
|
is a separate step, different from variable name mangling. Pass
|
||||||
`--mangle-props` to enable it. It will mangle all properties in the
|
`--mangle-props` to enable it. It will mangle all properties in the
|
||||||
input code with the exception of built in DOM properties and properties
|
input code with the exception of built in DOM properties and properties
|
||||||
in core javascript classes. For example:
|
in core JavaScript classes. For example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// example.js
|
// example.js
|
||||||
@@ -238,7 +236,7 @@ x.bar_ = 2;
|
|||||||
x["baz_"] = 3;
|
x["baz_"] = 3;
|
||||||
console.log(x.calc());
|
console.log(x.calc());
|
||||||
```
|
```
|
||||||
Mangle all properties (except for javascript `builtins`):
|
Mangle all properties (except for JavaScript `builtins`):
|
||||||
```bash
|
```bash
|
||||||
$ uglifyjs example.js -c -m --mangle-props
|
$ uglifyjs example.js -c -m --mangle-props
|
||||||
```
|
```
|
||||||
@@ -510,11 +508,13 @@ 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_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
|
||||||
|
of function names. Useful for code relying on `Function.prototype.name`.
|
||||||
|
|
||||||
## Minify options structure
|
## Minify options structure
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
warnings: false,
|
|
||||||
parse: {
|
parse: {
|
||||||
// parse options
|
// parse options
|
||||||
},
|
},
|
||||||
@@ -537,6 +537,7 @@ if (result.error) throw result.error;
|
|||||||
nameCache: null, // or specify a name cache object
|
nameCache: null, // or specify a name cache object
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
ie8: false,
|
ie8: false,
|
||||||
|
warnings: false,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -590,111 +591,88 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
## Parse options
|
## Parse options
|
||||||
|
|
||||||
- `bare_returns` (default `false`) -- support top level `return` statements
|
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||||
|
|
||||||
- `html5_comments` (default `true`)
|
- `html5_comments` (default `true`)
|
||||||
|
|
||||||
- `shebang` (default `true`) -- support `#!command` as the first line
|
- `shebang` (default `true`) -- support `#!command` as the first line
|
||||||
|
|
||||||
## Compress options
|
## Compress options
|
||||||
|
|
||||||
- `sequences` (default: true) -- join consecutive simple statements using the
|
- `booleans` (default: `true`) -- various optimizations for boolean context, for example `!!a
|
||||||
comma operator. May be set to a positive integer to specify the maximum number
|
? b : c → a ? b : c`
|
||||||
of consecutive comma sequences that will be generated. If this option is set to
|
|
||||||
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
|
|
||||||
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
|
|
||||||
is grandfathered to be equivalent to `true` and as such means `200`. On rare
|
|
||||||
occasions the default sequences limit leads to very slow compress times in which
|
|
||||||
case a value of `20` or less is recommended.
|
|
||||||
|
|
||||||
- `properties` -- rewrite property access using the dot notation, for
|
- `cascade` (default: `true`) -- small optimization for sequences, transform `x, x` into `x`
|
||||||
example `foo["bar"] → foo.bar`
|
and `x = something(), x` into `x = something()`
|
||||||
|
|
||||||
- `dead_code` -- remove unreachable code
|
- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables - side
|
||||||
|
effects permitting.
|
||||||
|
|
||||||
- `drop_debugger` -- remove `debugger;` statements
|
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes, for example:
|
||||||
|
|
||||||
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
|
||||||
|
|
||||||
- `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to
|
|
||||||
allow improved compression. This might be unsafe when an at least one of two
|
|
||||||
operands is an object with computed values due the use of methods like `get`,
|
|
||||||
or `valueOf`. This could cause change in execution order after operands in the
|
|
||||||
comparison are switching. Compression only works if both `comparisons` and
|
|
||||||
`unsafe_comps` are both set to true.
|
|
||||||
|
|
||||||
- `unsafe_Func` (default: false) -- compress and mangle `Function(args, code)`
|
|
||||||
when both `args` and `code` are string literals.
|
|
||||||
|
|
||||||
- `unsafe_math` (default: false) -- optimize numerical expressions like
|
|
||||||
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
|
||||||
|
|
||||||
- `unsafe_proto` (default: false) -- optimize expressions like
|
|
||||||
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
|
||||||
|
|
||||||
- `unsafe_regexp` (default: false) -- enable substitutions of variables with
|
|
||||||
`RegExp` values the same way as if they are constants.
|
|
||||||
|
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
|
||||||
expressions
|
|
||||||
|
|
||||||
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
|
||||||
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
|
`!(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.
|
||||||
|
|
||||||
- `evaluate` -- attempt to evaluate constant expressions
|
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
|
||||||
|
expressions
|
||||||
|
|
||||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
- `dead_code` (default: `true`) -- remove unreachable code
|
||||||
? b : c → a ? b : c`
|
|
||||||
|
|
||||||
- `typeofs` -- default `true`. Transforms `typeof foo == "undefined"` into
|
- `drop_console` (default: `false`) -- default `false`. Pass `true` to discard calls to
|
||||||
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
`console.*` functions. If you wish to drop a specific function call
|
||||||
earlier versions due to known issues.
|
such as `console.info` and/or retain side effects from function arguments
|
||||||
|
after dropping the function call then use `pure_funcs` instead.
|
||||||
|
|
||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
|
||||||
statically determine the condition
|
|
||||||
|
|
||||||
- `unused` -- drop unreferenced functions and variables (simple direct variable
|
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
|
||||||
assignments do not count as references unless set to `"keep_assign"`)
|
|
||||||
|
|
||||||
- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
|
- `expression` (default: `false`) -- default `false`. Pass `true` to preserve completion values
|
||||||
in the top level scope (`false` by default, `true` to drop both unreferenced
|
from terminal statements without `return`, e.g. in bookmarklets.
|
||||||
functions and variables)
|
|
||||||
|
|
||||||
- `top_retain` -- prevent specific toplevel functions and variables from `unused`
|
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
|
||||||
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
|
|
||||||
|
|
||||||
- `hoist_funs` -- hoist function declarations
|
- `hoist_funs` (default: `true`) -- hoist function declarations
|
||||||
|
|
||||||
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
|
- `hoist_props` (default: `false`) -- hoist properties from constant object and
|
||||||
|
array literals into regular variables subject to a set of constraints. For example:
|
||||||
|
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
|
||||||
|
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
|
||||||
|
and the `compress` option `toplevel` enabled.
|
||||||
|
|
||||||
|
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
|
||||||
by default because it seems to increase the size of the output in general)
|
by default because it seems to increase the size of the output in general)
|
||||||
|
|
||||||
- `if_return` -- optimizations for if/return and if/continue
|
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
|
||||||
|
|
||||||
- `inline` -- embed simple functions
|
- `inline` (default: `true`) -- embed simple functions
|
||||||
|
|
||||||
- `join_vars` -- join consecutive `var` statements
|
- `join_vars` (default: `true`) -- join consecutive `var` statements
|
||||||
|
|
||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `keep_fargs` (default: `true`) -- default `true`. Prevents the
|
||||||
and `x = something(), x` into `x = something()`
|
compressor from discarding unused function arguments. You need this
|
||||||
|
for code which relies on `Function.length`.
|
||||||
|
|
||||||
- `collapse_vars` -- Collapse single-use non-constant variables - side
|
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
|
||||||
effects permitting.
|
compressor from discarding function names. Useful for code relying on
|
||||||
|
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||||
|
|
||||||
- `reduce_vars` -- Improve optimization on variables assigned with and
|
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
used as constant values.
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
declarations etc.
|
statically determine the condition
|
||||||
|
|
||||||
- `negate_iife` -- 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
|
||||||
code generator would insert.
|
code generator would insert.
|
||||||
|
|
||||||
- `pure_getters` -- the default is `false`. If you pass `true` for
|
- `passes` (default: `1`) -- The maximum number of times to run compress.
|
||||||
this, UglifyJS will assume that object property access
|
In some cases more than one pass leads to further compressed code. Keep in
|
||||||
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
mind more passes will take more time.
|
||||||
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
|
|
||||||
`foo` is certain to not throw, i.e. not `null` or `undefined`.
|
|
||||||
|
|
||||||
- `pure_funcs` -- default `null`. You can pass an array of names and
|
- `properties` (default: `true`) -- rewrite property access using the dot notation, for
|
||||||
|
example `foo["bar"] → foo.bar`
|
||||||
|
|
||||||
|
- `pure_funcs` (default: `null`) -- You can pass an array of names and
|
||||||
UglifyJS will assume that those functions do not produce side
|
UglifyJS will assume that those functions do not produce side
|
||||||
effects. DANGER: will not check if the name is redefined in scope.
|
effects. DANGER: will not check if the name is redefined in scope.
|
||||||
An example case here, for instance `var q = Math.floor(a/b)`. If
|
An example case here, for instance `var q = Math.floor(a/b)`. If
|
||||||
@@ -705,49 +683,84 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
statement would get discarded. The current implementation adds some
|
statement would get discarded. The current implementation adds some
|
||||||
overhead (compression will be slower).
|
overhead (compression will be slower).
|
||||||
|
|
||||||
- `drop_console` -- default `false`. Pass `true` to discard calls to
|
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
|
||||||
`console.*` functions. If you wish to drop a specific function call
|
this, UglifyJS will assume that object property access
|
||||||
such as `console.info` and/or retain side effects from function arguments
|
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
||||||
after dropping the function call then use `pure_funcs` instead.
|
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
|
||||||
|
`foo` is certain to not throw, i.e. not `null` or `undefined`.
|
||||||
|
|
||||||
- `expression` -- default `false`. Pass `true` to preserve completion values
|
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
|
||||||
from terminal statements without `return`, e.g. in bookmarklets.
|
used as constant values.
|
||||||
|
|
||||||
- `keep_fargs` -- default `true`. Prevents the
|
- `sequences` (default: `true`) -- join consecutive simple statements using the
|
||||||
compressor from discarding unused function arguments. You need this
|
comma operator. May be set to a positive integer to specify the maximum number
|
||||||
for code which relies on `Function.length`.
|
of consecutive comma sequences that will be generated. If this option is set to
|
||||||
|
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
|
||||||
|
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
|
||||||
|
is grandfathered to be equivalent to `true` and as such means `200`. On rare
|
||||||
|
occasions the default sequences limit leads to very slow compress times in which
|
||||||
|
case a value of `20` or less is recommended.
|
||||||
|
|
||||||
- `keep_fnames` -- default `false`. Pass `true` to prevent the
|
- `side_effects` (default: `true`) -- default `true`. Pass `false` to disable potentially dropping
|
||||||
compressor from discarding function names. Useful for code relying on
|
|
||||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
|
||||||
|
|
||||||
- `passes` -- default `1`. The maximum number of times to run compress.
|
|
||||||
In some cases more than one pass leads to further compressed code. Keep in
|
|
||||||
mind more passes will take more time.
|
|
||||||
|
|
||||||
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
|
||||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
|
||||||
|
|
||||||
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
|
|
||||||
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
|
||||||
|
|
||||||
|
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
|
||||||
|
in the top level scope (`false` by default, `true` to drop both unreferenced
|
||||||
|
functions and variables)
|
||||||
|
|
||||||
|
- `top_retain` (default: `null`) -- prevent specific toplevel functions and variables from `unused`
|
||||||
|
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
|
||||||
|
|
||||||
|
- `typeofs` (default: `true`) -- default `true`. Transforms `typeof foo == "undefined"` into
|
||||||
|
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||||
|
earlier versions due to known issues.
|
||||||
|
|
||||||
|
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
|
- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
|
||||||
|
allow improved compression. This might be unsafe when an at least one of two
|
||||||
|
operands is an object with computed values due the use of methods like `get`,
|
||||||
|
or `valueOf`. This could cause change in execution order after operands in the
|
||||||
|
comparison are switching. Compression only works if both `comparisons` and
|
||||||
|
`unsafe_comps` are both set to true.
|
||||||
|
|
||||||
|
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
|
||||||
|
when both `args` and `code` are string literals.
|
||||||
|
|
||||||
|
- `unsafe_math` (default: `false`) -- optimize numerical expressions like
|
||||||
|
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
||||||
|
|
||||||
|
- `unsafe_proto` (default: `false`) -- optimize expressions like
|
||||||
|
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
||||||
|
|
||||||
|
- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
|
||||||
|
`RegExp` values the same way as if they are constants.
|
||||||
|
|
||||||
|
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple direct variable
|
||||||
|
assignments do not count as references unless set to `"keep_assign"`)
|
||||||
|
|
||||||
|
- `warnings` (default: `false`) -- display warnings when dropping unreachable code or unused
|
||||||
|
declarations etc.
|
||||||
|
|
||||||
## Mangle options
|
## Mangle options
|
||||||
|
|
||||||
|
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
||||||
|
where `eval` or `with` are used.
|
||||||
|
|
||||||
|
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
|
||||||
|
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
|
||||||
|
[compress option](#compress-options).
|
||||||
|
|
||||||
- `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.
|
||||||
|
|
||||||
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
|
|
||||||
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
|
|
||||||
[compress option](#compress-options).
|
|
||||||
|
|
||||||
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
|
||||||
where `eval` or `with` are used.
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -772,16 +785,20 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
|
|||||||
|
|
||||||
### Mangle properties options
|
### Mangle properties options
|
||||||
|
|
||||||
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
|
|
||||||
`reserved` array.
|
|
||||||
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
|
|
||||||
names matching the regular expression.
|
|
||||||
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
|
|
||||||
- `debug` (default: `false`) -— Mangle names with the original name still present.
|
|
||||||
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
|
|
||||||
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
|
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
|
||||||
DOM properties. Not recommended to override this setting.
|
DOM properties. Not recommended to override this setting.
|
||||||
|
|
||||||
|
- `debug` (default: `false`) -— Mangle names with the original name still present.
|
||||||
|
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
|
||||||
|
|
||||||
|
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
|
||||||
|
|
||||||
|
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
|
||||||
|
names matching the regular expression.
|
||||||
|
|
||||||
|
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
|
||||||
|
`reserved` array.
|
||||||
|
|
||||||
## Output options
|
## Output options
|
||||||
|
|
||||||
The code generator tries to output shortest code possible by default. In
|
The code generator tries to output shortest code possible by default. In
|
||||||
@@ -790,31 +807,43 @@ can pass additional arguments that control the code output:
|
|||||||
|
|
||||||
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
||||||
regexps (affects directives with non-ascii characters becoming invalid)
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
|
|
||||||
- `beautify` (default `true`) -- whether to actually beautify the output.
|
- `beautify` (default `true`) -- whether to actually beautify the output.
|
||||||
Passing `-b` will set this to true, but you might need to pass `-b` even
|
Passing `-b` will set this to true, but you might need to pass `-b` even
|
||||||
when you want to generate minified code, in order to specify additional
|
when you want to generate minified code, in order to specify additional
|
||||||
arguments, so you can use `-b beautify=false` to override it.
|
arguments, so you can use `-b beautify=false` to override it.
|
||||||
|
|
||||||
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
||||||
`do`, `while` or `with` statements, even if their body is a single
|
`do`, `while` or `with` statements, even if their body is a single
|
||||||
statement.
|
statement.
|
||||||
|
|
||||||
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||||
comments, `"some"` to preserve some comments, a regular expression string
|
comments, `"some"` to preserve some comments, a regular expression string
|
||||||
(e.g. `/^!/`) or a function.
|
(e.g. `/^!/`) or a function.
|
||||||
- `indent_level` (default 4)
|
|
||||||
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
- `indent_level` (default `4`)
|
||||||
|
|
||||||
|
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
||||||
|
|
||||||
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
||||||
`</script` in strings
|
`</script` in strings
|
||||||
|
|
||||||
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
quotes from property names in object literals.
|
quotes from property names in object literals.
|
||||||
|
|
||||||
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
||||||
|
|
||||||
- `preamble` (default `null`) -- when passed it must be a string and
|
- `preamble` (default `null`) -- when passed it must be a string and
|
||||||
it will be prepended to the output literally. The source map will
|
it will be prepended to the output literally. The source map will
|
||||||
adjust for this text. Can be used to insert a comment containing
|
adjust for this text. Can be used to insert a comment containing
|
||||||
licensing information, for example.
|
licensing information, for example.
|
||||||
|
|
||||||
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
||||||
only works if `beautify` is set to `false`.
|
only works if `beautify` is set to `false`.
|
||||||
|
|
||||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||||
objects
|
objects
|
||||||
|
|
||||||
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
||||||
quoted property names and directives as well):
|
quoted property names and directives as well):
|
||||||
- `0` -- prefers double quotes, switches to single quotes when there are
|
- `0` -- prefers double quotes, switches to single quotes when there are
|
||||||
@@ -822,16 +851,20 @@ can pass additional arguments that control the code output:
|
|||||||
- `1` -- always use single quotes
|
- `1` -- always use single quotes
|
||||||
- `2` -- always use double quotes
|
- `2` -- always use double quotes
|
||||||
- `3` -- always use the original quotes
|
- `3` -- always use the original quotes
|
||||||
|
|
||||||
- `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
|
||||||
gzip could be smaller; size after gzip insignificantly larger).
|
gzip could be smaller; size after gzip insignificantly larger).
|
||||||
|
|
||||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
|
||||||
|
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
obey. It refers to the width of the line text (excluding indentation).
|
obey. It refers to the width of the line text (excluding indentation).
|
||||||
It doesn't work very well currently, but it does make the code generated
|
It doesn't work very well currently, but it does make the code generated
|
||||||
by UglifyJS more readable.
|
by UglifyJS more readable.
|
||||||
|
|
||||||
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
||||||
function expressions. See
|
function expressions. See
|
||||||
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
||||||
@@ -1033,7 +1066,7 @@ in total it's a bit more than just using UglifyJS's own parser.
|
|||||||
### Uglify Fast Minify Mode
|
### Uglify Fast Minify Mode
|
||||||
|
|
||||||
It's not well known, but whitespace removal and symbol mangling accounts
|
It's not well known, but whitespace removal and symbol mangling accounts
|
||||||
for 95% of the size reduction in minified code for most javascript - not
|
for 95% of the size reduction in minified code for most JavaScript - not
|
||||||
elaborate code transforms. One can simply disable `compress` to speed up
|
elaborate code transforms. One can simply disable `compress` to speed up
|
||||||
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
|
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
|
||||||
comparable minify speeds and gzip sizes to
|
comparable minify speeds and gzip sizes to
|
||||||
|
|||||||
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
|||||||
$documentation: "Represents a debugger statement",
|
$documentation: "Represents a debugger statement",
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||||
$documentation: "Represents a directive, like \"use strict\";",
|
$documentation: "Represents a directive, like \"use strict\";",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||||
scope: "[AST_Scope/S] The scope that this directive affects",
|
|
||||||
quote: "[string] the original quote character"
|
quote: "[string] the original quote character"
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
directives: "[string*/S] an array of directives declared in this scope",
|
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||||
|
|||||||
465
lib/compress.js
465
lib/compress.js
@@ -60,6 +60,7 @@ function Compressor(options, false_by_default) {
|
|||||||
expression : false,
|
expression : false,
|
||||||
global_defs : {},
|
global_defs : {},
|
||||||
hoist_funs : !false_by_default,
|
hoist_funs : !false_by_default,
|
||||||
|
hoist_props : false,
|
||||||
hoist_vars : false,
|
hoist_vars : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
@@ -151,7 +152,7 @@ merge(Compressor.prototype, {
|
|||||||
var last_count = 1 / 0;
|
var last_count = 1 / 0;
|
||||||
for (var pass = 0; pass < passes; pass++) {
|
for (var pass = 0; pass < passes; pass++) {
|
||||||
if (pass > 0 || this.option("reduce_vars"))
|
if (pass > 0 || this.option("reduce_vars"))
|
||||||
node.reset_opt_flags(this, true);
|
node.reset_opt_flags(this);
|
||||||
node = node.transform(this);
|
node = node.transform(this);
|
||||||
if (passes > 1) {
|
if (passes > 1) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
@@ -190,6 +191,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node._squeezed) return node;
|
if (node._squeezed) return node;
|
||||||
var was_scope = false;
|
var was_scope = false;
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
|
node = node.hoist_properties(this);
|
||||||
node = node.hoist_declarations(this);
|
node = node.hoist_declarations(this);
|
||||||
was_scope = true;
|
was_scope = true;
|
||||||
}
|
}
|
||||||
@@ -283,8 +285,13 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
|
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) {
|
||||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
|
var unused = compressor.option("unused");
|
||||||
|
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||||
|
// properly assigned before use:
|
||||||
|
// - `push()` & `pop()` when visiting conditional branches
|
||||||
|
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||||
var safe_ids = Object.create(null);
|
var safe_ids = Object.create(null);
|
||||||
var suppressor = new TreeWalker(function(node) {
|
var suppressor = new TreeWalker(function(node) {
|
||||||
if (!(node instanceof AST_Symbol)) return;
|
if (!(node instanceof AST_Symbol)) return;
|
||||||
@@ -293,6 +300,8 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
});
|
});
|
||||||
|
var in_loop = null;
|
||||||
|
var loop_ids = Object.create(null);
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
node._squeezed = false;
|
node._squeezed = false;
|
||||||
node._optimized = false;
|
node._optimized = false;
|
||||||
@@ -302,16 +311,25 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
d.references.push(node);
|
d.references.push(node);
|
||||||
if (d.fixed === undefined || !safe_to_read(d)
|
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
|
||||||
|| is_modified(node, 0, is_immutable(node.fixed_value()))) {
|
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
|
} else if (d.fixed) {
|
||||||
|
var value = node.fixed_value();
|
||||||
|
if (unused) {
|
||||||
|
d.single_use = value
|
||||||
|
&& d.references.length == 1
|
||||||
|
&& loop_ids[d.id] === in_loop
|
||||||
|
&& d.scope === node.scope
|
||||||
|
&& value.is_constant_expression();
|
||||||
|
}
|
||||||
|
if (is_modified(node, value, 0, is_immutable(value))) {
|
||||||
|
if (d.single_use) {
|
||||||
|
d.single_use = "m";
|
||||||
} else {
|
} else {
|
||||||
var parent = tw.parent();
|
d.fixed = false;
|
||||||
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
}
|
||||||
|| parent instanceof AST_Call && node !== parent.expression
|
} else {
|
||||||
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
mark_escaped(d, node, value, 0);
|
||||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
|
||||||
d.escaped = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,6 +343,7 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.value;
|
return node.value;
|
||||||
};
|
};
|
||||||
|
loop_ids[d.id] = in_loop;
|
||||||
mark(d, false);
|
mark(d, false);
|
||||||
descend();
|
descend();
|
||||||
} else {
|
} else {
|
||||||
@@ -380,6 +399,7 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||||
};
|
};
|
||||||
|
loop_ids[d.id] = in_loop;
|
||||||
mark(d, true);
|
mark(d, true);
|
||||||
} else {
|
} else {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
@@ -391,14 +411,12 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Accessor) {
|
if (node instanceof AST_Accessor) {
|
||||||
var save_ids = safe_ids;
|
push();
|
||||||
safe_ids = Object.create(null);
|
|
||||||
descend();
|
descend();
|
||||||
safe_ids = save_ids;
|
pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Binary
|
if (node instanceof AST_Binary && lazy_op(node.operator)) {
|
||||||
&& (node.operator == "&&" || node.operator == "||")) {
|
|
||||||
node.left.walk(tw);
|
node.left.walk(tw);
|
||||||
push();
|
push();
|
||||||
node.right.walk(tw);
|
node.right.walk(tw);
|
||||||
@@ -428,10 +446,13 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_DWLoop) {
|
if (node instanceof AST_DWLoop) {
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
push();
|
push();
|
||||||
node.condition.walk(tw);
|
node.condition.walk(tw);
|
||||||
node.body.walk(tw);
|
node.body.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
@@ -442,6 +463,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
if (node.init) node.init.walk(tw);
|
if (node.init) node.init.walk(tw);
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
if (node.condition) {
|
if (node.condition) {
|
||||||
push();
|
push();
|
||||||
node.condition.walk(tw);
|
node.condition.walk(tw);
|
||||||
@@ -455,14 +478,18 @@ merge(Compressor.prototype, {
|
|||||||
node.step.walk(tw);
|
node.step.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
}
|
}
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_ForIn) {
|
if (node instanceof AST_ForIn) {
|
||||||
node.init.walk(suppressor);
|
node.init.walk(suppressor);
|
||||||
node.object.walk(tw);
|
node.object.walk(tw);
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
push();
|
push();
|
||||||
node.body.walk(tw);
|
node.body.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Try) {
|
if (node instanceof AST_Try) {
|
||||||
@@ -522,6 +549,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reset_def(def) {
|
function reset_def(def) {
|
||||||
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval) {
|
if (def.scope.uses_eval) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
@@ -532,24 +560,68 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def.references = [];
|
def.references = [];
|
||||||
def.should_replace = undefined;
|
def.should_replace = undefined;
|
||||||
|
def.single_use = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_immutable(value) {
|
function is_immutable(value) {
|
||||||
return value && value.is_constant() || value instanceof AST_Lambda;
|
return value && (value.is_constant() || value instanceof AST_Lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_modified(node, level, immutable) {
|
function read_property(obj, key) {
|
||||||
|
if (key instanceof AST_Constant) key = key.getValue();
|
||||||
|
if (key instanceof AST_Node) return null;
|
||||||
|
var value;
|
||||||
|
if (obj instanceof AST_Array) {
|
||||||
|
var elements = obj.elements;
|
||||||
|
if (key == "length") return make_node_from_constant(elements.length, obj);
|
||||||
|
if (typeof key == "number" && key in elements) value = elements[key];
|
||||||
|
} else if (obj instanceof AST_Object) {
|
||||||
|
var props = obj.properties;
|
||||||
|
for (var i = props.length; --i >= 0;) {
|
||||||
|
var prop = props[i];
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) return;
|
||||||
|
if (!value && props[i].key === key) value = props[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_modified(node, value, level, immutable) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
if (is_lhs(node, parent)
|
if (is_lhs(node, parent)
|
||||||
|| !immutable && parent instanceof AST_Call && parent.expression === node) {
|
|| !immutable
|
||||||
|
&& parent instanceof AST_Call
|
||||||
|
&& parent.expression === node
|
||||||
|
&& (!(value instanceof AST_Function) || value.contains_this())) {
|
||||||
return true;
|
return true;
|
||||||
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
|
return is_modified(parent, parent, level + 1);
|
||||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||||
return !immutable && is_modified(parent, level + 1);
|
return !immutable && is_modified(parent, read_property(value, parent.property), level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mark_escaped(d, node, value, level) {
|
||||||
|
var parent = tw.parent(level);
|
||||||
|
if (value instanceof AST_Constant || value instanceof AST_Function) return;
|
||||||
|
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|
||||||
|
|| parent instanceof AST_Call && node !== parent.expression
|
||||||
|
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
||||||
|
|| parent instanceof AST_VarDef && node === parent.value) {
|
||||||
|
d.escaped = true;
|
||||||
|
return;
|
||||||
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
|
mark_escaped(d, parent, parent, level + 1);
|
||||||
|
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
||||||
|
value = read_property(value, parent.property);
|
||||||
|
mark_escaped(d, parent, value, level + 1);
|
||||||
|
if (value) return;
|
||||||
|
}
|
||||||
|
if (level == 0) d.direct_access = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("fixed_value", function() {
|
AST_Symbol.DEFMETHOD("fixed_value", function() {
|
||||||
var fixed = this.definition().fixed;
|
var fixed = this.definition().fixed;
|
||||||
if (!fixed || fixed instanceof AST_Node) return fixed;
|
if (!fixed || fixed instanceof AST_Node) return fixed;
|
||||||
return fixed();
|
return fixed();
|
||||||
@@ -561,6 +633,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function is_lhs_read_only(lhs) {
|
function is_lhs_read_only(lhs) {
|
||||||
|
if (lhs instanceof AST_This) return true;
|
||||||
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||||
if (lhs instanceof AST_PropAccess) {
|
if (lhs instanceof AST_PropAccess) {
|
||||||
lhs = lhs.expression;
|
lhs = lhs.expression;
|
||||||
@@ -693,7 +766,7 @@ merge(Compressor.prototype, {
|
|||||||
return node instanceof AST_SymbolRef && node.definition().undeclared;
|
return node instanceof AST_SymbolRef && node.definition().undeclared;
|
||||||
}
|
}
|
||||||
|
|
||||||
var global_names = makePredicate("Array Boolean console Error Function Math Number RegExp Object String");
|
var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError");
|
||||||
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
|
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
|
||||||
return !this.definition().undeclared
|
return !this.definition().undeclared
|
||||||
|| compressor.option("unsafe") && global_names(this.name);
|
|| compressor.option("unsafe") && global_names(this.name);
|
||||||
@@ -745,10 +818,11 @@ merge(Compressor.prototype, {
|
|||||||
while (candidates.length > 0) {
|
while (candidates.length > 0) {
|
||||||
var candidate = candidates.pop();
|
var candidate = candidates.pop();
|
||||||
var lhs = get_lhs(candidate);
|
var lhs = get_lhs(candidate);
|
||||||
if (!lhs || is_lhs_read_only(lhs)) continue;
|
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
|
||||||
// Locate symbols which may execute code outside of scanning range
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||||
|
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
|
||||||
var side_effects = value_has_side_effects(candidate);
|
var side_effects = value_has_side_effects(candidate);
|
||||||
var hit = candidate.name instanceof AST_SymbolFunarg;
|
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||||
var abort = false, replaced = false;
|
var abort = false, replaced = false;
|
||||||
@@ -809,16 +883,17 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_Call
|
if (node instanceof AST_Call
|
||||||
|| node instanceof AST_Exit
|
|| node instanceof AST_Exit
|
||||||
|| node instanceof AST_PropAccess
|
|| node instanceof AST_PropAccess
|
||||||
|
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
||||||
|| node instanceof AST_SymbolRef
|
|| node instanceof AST_SymbolRef
|
||||||
&& (lvalues[node.name]
|
&& (lvalues[node.name]
|
||||||
|| side_effects && !references_in_scope(node.definition()))
|
|| side_effects && !references_in_scope(node.definition()))
|
||||||
|| (sym = lhs_or_def(node)) && get_symbol(sym).name in lvalues
|
|| (sym = lhs_or_def(node))
|
||||||
|| parent instanceof AST_Binary
|
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|
||||||
&& (parent.operator == "&&" || parent.operator == "||")
|
|| (side_effects || !one_off)
|
||||||
|
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|
||||||
|| parent instanceof AST_Case
|
|| parent instanceof AST_Case
|
||||||
|| parent instanceof AST_Conditional
|
|| parent instanceof AST_Conditional
|
||||||
|| parent instanceof AST_For
|
|| parent instanceof AST_If)) {
|
||||||
|| parent instanceof AST_If) {
|
|
||||||
if (!(node instanceof AST_Scope)) descend(node, tt);
|
if (!(node instanceof AST_Scope)) descend(node, tt);
|
||||||
abort = true;
|
abort = true;
|
||||||
return node;
|
return node;
|
||||||
@@ -841,13 +916,15 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.uses_eval
|
&& !fn.uses_eval
|
||||||
&& (iife = compressor.parent()) instanceof AST_Call
|
&& (iife = compressor.parent()) instanceof AST_Call
|
||||||
&& iife.expression === fn) {
|
&& iife.expression === fn) {
|
||||||
|
var fn_strict = compressor.has_directive("use strict");
|
||||||
|
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
for (var i = fn.argnames.length; --i >= 0;) {
|
for (var i = fn.argnames.length; --i >= 0;) {
|
||||||
var sym = fn.argnames[i];
|
var sym = fn.argnames[i];
|
||||||
if (sym.name in names) continue;
|
if (sym.name in names) continue;
|
||||||
names[sym.name] = true;
|
names[sym.name] = true;
|
||||||
var arg = iife.args[i];
|
var arg = iife.args[i];
|
||||||
if (!arg) arg = make_node(AST_Undefined, sym);
|
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||||
else {
|
else {
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (!arg) return true;
|
if (!arg) return true;
|
||||||
@@ -858,7 +935,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
arg = null;
|
arg = null;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
|
||||||
arg = null;
|
arg = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -902,28 +979,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_symbol(node) {
|
|
||||||
while (node instanceof AST_PropAccess) node = node.expression;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = Object.create(null);
|
var lvalues = Object.create(null);
|
||||||
if (expr instanceof AST_Unary) return lvalues;
|
if (expr instanceof AST_Unary) return lvalues;
|
||||||
var scope;
|
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_Scope) {
|
var sym = node;
|
||||||
var save_scope = scope;
|
while (sym instanceof AST_PropAccess) sym = sym.expression;
|
||||||
descend();
|
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
|
||||||
scope = save_scope;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_SymbolRef || node instanceof AST_PropAccess) {
|
|
||||||
var sym = get_symbol(node);
|
|
||||||
if (sym instanceof AST_SymbolRef) {
|
|
||||||
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
|
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
@@ -1399,9 +1463,10 @@ merge(Compressor.prototype, {
|
|||||||
return member(this.operator, unary_bool);
|
return member(this.operator, unary_bool);
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(){
|
def(AST_Binary, function(){
|
||||||
return member(this.operator, binary_bool) ||
|
return member(this.operator, binary_bool)
|
||||||
( (this.operator == "&&" || this.operator == "||") &&
|
|| lazy_op(this.operator)
|
||||||
this.left.is_boolean() && this.right.is_boolean() );
|
&& this.left.is_boolean()
|
||||||
|
&& this.right.is_boolean();
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(){
|
def(AST_Conditional, function(){
|
||||||
return this.consequent.is_boolean() && this.alternative.is_boolean();
|
return this.consequent.is_boolean() && this.alternative.is_boolean();
|
||||||
@@ -1470,6 +1535,7 @@ merge(Compressor.prototype, {
|
|||||||
node.DEFMETHOD("is_string", func);
|
node.DEFMETHOD("is_string", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var lazy_op = makePredicate("&& ||");
|
||||||
var unary_side_effects = makePredicate("delete ++ --");
|
var unary_side_effects = makePredicate("delete ++ --");
|
||||||
|
|
||||||
function is_lhs(node, parent) {
|
function is_lhs(node, parent) {
|
||||||
@@ -1581,35 +1647,6 @@ merge(Compressor.prototype, {
|
|||||||
&& unaryPrefix(this.operator);
|
&& unaryPrefix(this.operator);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Obtain the constant value of an expression already known to be constant.
|
|
||||||
// Result only valid iff this.is_constant() is true.
|
|
||||||
AST_Node.DEFMETHOD("constant_value", function(compressor){
|
|
||||||
// Accomodate when option evaluate=false.
|
|
||||||
if (this instanceof AST_Constant && !(this instanceof AST_RegExp)) {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
// Accomodate the common constant expressions !0 and -1 when option evaluate=false.
|
|
||||||
if (this instanceof AST_UnaryPrefix
|
|
||||||
&& this.expression instanceof AST_Constant) switch (this.operator) {
|
|
||||||
case "!":
|
|
||||||
return !this.expression.value;
|
|
||||||
case "~":
|
|
||||||
return ~this.expression.value;
|
|
||||||
case "-":
|
|
||||||
return -this.expression.value;
|
|
||||||
case "+":
|
|
||||||
return +this.expression.value;
|
|
||||||
default:
|
|
||||||
throw new Error(string_template("Cannot evaluate unary expression {value}", {
|
|
||||||
value: this.print_to_string()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
var result = this.evaluate(compressor);
|
|
||||||
if (result !== this) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
|
||||||
});
|
|
||||||
def(AST_Statement, function(){
|
def(AST_Statement, function(){
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
@@ -1628,6 +1665,7 @@ merge(Compressor.prototype, {
|
|||||||
var elements = [];
|
var elements = [];
|
||||||
for (var i = 0, len = this.elements.length; i < len; i++) {
|
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||||
var element = this.elements[i];
|
var element = this.elements[i];
|
||||||
|
if (element instanceof AST_Function) continue;
|
||||||
var value = ev(element, compressor);
|
var value = ev(element, compressor);
|
||||||
if (element === value) return this;
|
if (element === value) return this;
|
||||||
elements.push(value);
|
elements.push(value);
|
||||||
@@ -1651,6 +1689,7 @@ merge(Compressor.prototype, {
|
|||||||
if (typeof Object.prototype[key] === 'function') {
|
if (typeof Object.prototype[key] === 'function') {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
if (prop.value instanceof AST_Function) continue;
|
||||||
val[key] = ev(prop.value, compressor);
|
val[key] = ev(prop.value, compressor);
|
||||||
if (val[key] === prop.value) return this;
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
@@ -1980,16 +2019,27 @@ merge(Compressor.prototype, {
|
|||||||
if (!compressor.option("side_effects")) return false;
|
if (!compressor.option("side_effects")) return false;
|
||||||
if (this.pure !== undefined) return this.pure;
|
if (this.pure !== undefined) return this.pure;
|
||||||
var pure = false;
|
var pure = false;
|
||||||
var comments, last_comment;
|
var comments, pure_comment;
|
||||||
if (this.start
|
if (this.start
|
||||||
&& (comments = this.start.comments_before)
|
&& (comments = this.start.comments_before)
|
||||||
&& comments.length
|
&& comments.length
|
||||||
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
|
&& (pure_comment = find_if(function (comment) {
|
||||||
pure = last_comment;
|
return /[@#]__PURE__/.test(comment.value);
|
||||||
|
}, comments))) {
|
||||||
|
pure = pure_comment;
|
||||||
}
|
}
|
||||||
return this.pure = pure;
|
return this.pure = pure;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
|
||||||
|
AST_Call.DEFMETHOD("is_expr_pure", function(compressor) {
|
||||||
|
if (compressor.option("unsafe")) {
|
||||||
|
var expr = this.expression;
|
||||||
|
if (is_undeclared_ref(expr) && global_pure_fns(expr.name)) return true;
|
||||||
|
}
|
||||||
|
return this.has_pure_annotation(compressor) || !compressor.pure_funcs(this);
|
||||||
|
});
|
||||||
|
|
||||||
// determine if expression has side effects
|
// determine if expression has side effects
|
||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Node, return_true);
|
def(AST_Node, return_true);
|
||||||
@@ -1999,7 +2049,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_This, return_false);
|
def(AST_This, return_false);
|
||||||
|
|
||||||
def(AST_Call, function(compressor){
|
def(AST_Call, function(compressor){
|
||||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return true;
|
if (!this.is_expr_pure(compressor)) return true;
|
||||||
for (var i = this.args.length; --i >= 0;) {
|
for (var i = this.args.length; --i >= 0;) {
|
||||||
if (this.args[i].has_side_effects(compressor))
|
if (this.args[i].has_side_effects(compressor))
|
||||||
return true;
|
return true;
|
||||||
@@ -2098,6 +2148,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_Constant, return_true);
|
def(AST_Constant, return_true);
|
||||||
|
def(AST_Function, function(){
|
||||||
|
var self = this;
|
||||||
|
var result = true;
|
||||||
|
self.walk(new TreeWalker(function(node) {
|
||||||
|
if (!result) return true;
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
var def = node.definition();
|
||||||
|
if (self.enclosed.indexOf(def) >= 0
|
||||||
|
&& self.variables.get(def.name) !== def) {
|
||||||
|
result = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
|
});
|
||||||
def(AST_Unary, function(){
|
def(AST_Unary, function(){
|
||||||
return this.expression.is_constant_expression();
|
return this.expression.is_constant_expression();
|
||||||
});
|
});
|
||||||
@@ -2181,7 +2247,6 @@ merge(Compressor.prototype, {
|
|||||||
if (self.uses_eval || self.uses_with) return;
|
if (self.uses_eval || self.uses_with) return;
|
||||||
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
||||||
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||||
if (!drop_funcs && !drop_vars) return;
|
|
||||||
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
|
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
|
||||||
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
|
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
|
||||||
return node.left;
|
return node.left;
|
||||||
@@ -2316,7 +2381,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) {
|
var parent = tt.parent();
|
||||||
|
if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
|
||||||
// place uninitialized names at the start
|
// place uninitialized names at the start
|
||||||
var body = [], head = [], tail = [];
|
var body = [], head = [], tail = [];
|
||||||
// for unused names whose initialization has
|
// for unused names whose initialization has
|
||||||
@@ -2326,7 +2392,7 @@ merge(Compressor.prototype, {
|
|||||||
node.definitions.forEach(function(def) {
|
node.definitions.forEach(function(def) {
|
||||||
if (def.value) def.value = def.value.transform(tt);
|
if (def.value) def.value = def.value.transform(tt);
|
||||||
var sym = def.name.definition();
|
var sym = def.name.definition();
|
||||||
if (sym.id in in_use_ids) {
|
if (!drop_vars || sym.id in in_use_ids) {
|
||||||
if (def.name instanceof AST_SymbolVar) {
|
if (def.name instanceof AST_SymbolVar) {
|
||||||
var var_defs = var_defs_by_id.get(sym.id);
|
var var_defs = var_defs_by_id.get(sym.id);
|
||||||
if (var_defs.length > 1 && !def.value) {
|
if (var_defs.length > 1 && !def.value) {
|
||||||
@@ -2408,7 +2474,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !((def = def.definition()).id in in_use_ids)
|
&& !((def = def.definition()).id in in_use_ids)
|
||||||
&& self.variables.get(def.name) === def) {
|
&& self.variables.get(def.name) === def) {
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||||
}
|
}
|
||||||
return make_node(AST_Number, node, {
|
return make_node(AST_Number, node, {
|
||||||
value: 0
|
value: 0
|
||||||
@@ -2423,17 +2489,18 @@ merge(Compressor.prototype, {
|
|||||||
// We fix it at this stage by moving the `var` outside the `for`.
|
// We fix it at this stage by moving the `var` outside the `for`.
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
|
var block;
|
||||||
if (node.init instanceof AST_BlockStatement) {
|
if (node.init instanceof AST_BlockStatement) {
|
||||||
var block = node.init;
|
block = node.init;
|
||||||
node.init = block.body.pop();
|
node.init = block.body.pop();
|
||||||
block.body.push(node);
|
block.body.push(node);
|
||||||
return in_list ? MAP.splice(block.body) : block;
|
}
|
||||||
} else if (node.init instanceof AST_SimpleStatement) {
|
if (node.init instanceof AST_SimpleStatement) {
|
||||||
node.init = node.init.body;
|
node.init = node.init.body;
|
||||||
} else if (is_empty(node.init)) {
|
} else if (is_empty(node.init)) {
|
||||||
node.init = null;
|
node.init = null;
|
||||||
}
|
}
|
||||||
return node;
|
return !block ? node : in_list ? MAP.splice(block.body) : block;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
@@ -2591,6 +2658,71 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
|
||||||
|
var self = this;
|
||||||
|
if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
|
||||||
|
var defs_by_id = Object.create(null);
|
||||||
|
var var_names = Object.create(null);
|
||||||
|
self.enclosed.forEach(function(def) {
|
||||||
|
var_names[def.name] = true;
|
||||||
|
});
|
||||||
|
self.variables.each(function(def, name) {
|
||||||
|
var_names[name] = true;
|
||||||
|
});
|
||||||
|
return self.transform(new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_VarDef) {
|
||||||
|
var sym = node.name, def, value;
|
||||||
|
if (sym.scope === self
|
||||||
|
&& !(def = sym.definition()).escaped
|
||||||
|
&& !def.single_use
|
||||||
|
&& !def.direct_access
|
||||||
|
&& (value = sym.fixed_value()) === node.value
|
||||||
|
&& value instanceof AST_Object) {
|
||||||
|
var defs = new Dictionary();
|
||||||
|
var assignments = [];
|
||||||
|
value.properties.forEach(function(prop) {
|
||||||
|
assignments.push(make_node(AST_VarDef, node, {
|
||||||
|
name: make_sym(prop.key),
|
||||||
|
value: prop.value
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
defs_by_id[def.id] = defs;
|
||||||
|
return MAP.splice(assignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
|
||||||
|
var defs = defs_by_id[node.expression.definition().id];
|
||||||
|
if (defs) {
|
||||||
|
var key = node.property;
|
||||||
|
if (key instanceof AST_Node) key = key.getValue();
|
||||||
|
var def = defs.get(key);
|
||||||
|
var sym = make_node(AST_SymbolRef, node, {
|
||||||
|
name: def.name,
|
||||||
|
scope: node.expression.scope,
|
||||||
|
thedef: def
|
||||||
|
});
|
||||||
|
sym.reference({});
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_sym(key) {
|
||||||
|
var prefix = sym.name + "_" + key.toString().replace(/[^a-z_$]+/ig, "_");
|
||||||
|
var name = prefix;
|
||||||
|
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
|
||||||
|
var new_var = make_node(sym.CTOR, sym, {
|
||||||
|
name: name,
|
||||||
|
scope: self
|
||||||
|
});
|
||||||
|
var def = self.def_variable(new_var);
|
||||||
|
defs.set(key, def);
|
||||||
|
self.enclosed.push(def);
|
||||||
|
var_names[name] = true;
|
||||||
|
return new_var;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
// drop_side_effect_free()
|
// drop_side_effect_free()
|
||||||
// remove side-effect-free parts which only affects return value
|
// remove side-effect-free parts which only affects return value
|
||||||
(function(def){
|
(function(def){
|
||||||
@@ -2617,7 +2749,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Constant, return_null);
|
def(AST_Constant, return_null);
|
||||||
def(AST_This, return_null);
|
def(AST_This, return_null);
|
||||||
def(AST_Call, function(compressor, first_in_statement){
|
def(AST_Call, function(compressor, first_in_statement){
|
||||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) {
|
if (!this.is_expr_pure(compressor)) {
|
||||||
if (this.expression instanceof AST_Function
|
if (this.expression instanceof AST_Function
|
||||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
@@ -2638,14 +2770,12 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Binary, function(compressor, first_in_statement){
|
def(AST_Binary, function(compressor, first_in_statement){
|
||||||
var right = this.right.drop_side_effect_free(compressor);
|
var right = this.right.drop_side_effect_free(compressor);
|
||||||
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
switch (this.operator) {
|
if (lazy_op(this.operator)) {
|
||||||
case "&&":
|
|
||||||
case "||":
|
|
||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
node.right = right;
|
node.right = right;
|
||||||
return node;
|
return node;
|
||||||
default:
|
} else {
|
||||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||||
return make_sequence(this, [ left, right ]);
|
return make_sequence(this, [ left, right ]);
|
||||||
@@ -3112,6 +3242,7 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
if (reduce_vars) name.definition().fixed = false;
|
if (reduce_vars) name.definition().fixed = false;
|
||||||
}
|
}
|
||||||
|
remove(def.name.definition().orig, def.name);
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
@@ -3483,7 +3614,7 @@ merge(Compressor.prototype, {
|
|||||||
&& (left.operator == "++" || left.operator == "--")) {
|
&& (left.operator == "++" || left.operator == "--")) {
|
||||||
left = left.expression;
|
left = left.expression;
|
||||||
} else left = null;
|
} else left = null;
|
||||||
if (!left || is_lhs_read_only(left)) {
|
if (!left || is_lhs_read_only(left) || left.has_side_effects(compressor)) {
|
||||||
expressions[++i] = cdr;
|
expressions[++i] = cdr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3510,7 +3641,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
|
||||||
if (cdr.left.is_constant()) {
|
if (cdr.left.is_constant()) {
|
||||||
if (cdr.operator == "||" || cdr.operator == "&&") {
|
if (lazy_op(cdr.operator)) {
|
||||||
expressions[++i] = expressions[j];
|
expressions[++i] = expressions[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3666,6 +3797,11 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
|
function is_object(node) {
|
||||||
|
return node instanceof AST_Array
|
||||||
|
|| node instanceof AST_Lambda
|
||||||
|
|| node instanceof AST_Object;
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
function reversible() {
|
function reversible() {
|
||||||
@@ -3701,7 +3837,8 @@ merge(Compressor.prototype, {
|
|||||||
case "!==":
|
case "!==":
|
||||||
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
|
||||||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
|
||||||
(self.left.is_boolean() && self.right.is_boolean())) {
|
(self.left.is_boolean() && self.right.is_boolean()) ||
|
||||||
|
self.left.equivalent_to(self.right)) {
|
||||||
self.operator = self.operator.substr(0, 2);
|
self.operator = self.operator.substr(0, 2);
|
||||||
}
|
}
|
||||||
// XXX: intentionally falling down to the next case
|
// XXX: intentionally falling down to the next case
|
||||||
@@ -3721,6 +3858,13 @@ merge(Compressor.prototype, {
|
|||||||
if (self.operator.length == 2) self.operator += "=";
|
if (self.operator.length == 2) self.operator += "=";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// obj !== obj => false
|
||||||
|
else if (self.left instanceof AST_SymbolRef
|
||||||
|
&& self.right instanceof AST_SymbolRef
|
||||||
|
&& self.left.definition() === self.right.definition()
|
||||||
|
&& is_object(self.left.fixed_value())) {
|
||||||
|
return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
||||||
@@ -4010,8 +4154,7 @@ merge(Compressor.prototype, {
|
|||||||
// "x" + (y + "z")==> "x" + y + "z"
|
// "x" + (y + "z")==> "x" + y + "z"
|
||||||
if (self.right instanceof AST_Binary
|
if (self.right instanceof AST_Binary
|
||||||
&& self.right.operator == self.operator
|
&& self.right.operator == self.operator
|
||||||
&& (self.operator == "&&"
|
&& (lazy_op(self.operator)
|
||||||
|| self.operator == "||"
|
|
||||||
|| (self.operator == "+"
|
|| (self.operator == "+"
|
||||||
&& (self.right.left.is_string(compressor)
|
&& (self.right.left.is_string(compressor)
|
||||||
|| (self.left.is_string(compressor)
|
|| (self.left.is_string(compressor)
|
||||||
@@ -4059,12 +4202,14 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||||
}
|
}
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fixed instanceof AST_Function
|
&& fixed
|
||||||
&& d.references.length == 1
|
&& d.references.length == 1
|
||||||
|
&& (d.single_use || fixed instanceof AST_Function
|
||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
&& !d.scope.uses_eval
|
&& !d.scope.uses_eval
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
|
||||||
return fixed.clone(true);
|
var value = fixed.optimize(compressor);
|
||||||
|
return value === fixed ? fixed.clone(true) : value;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (compressor.option("evaluate") && fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
@@ -4392,19 +4537,69 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Sub, function(self, compressor){
|
OPT(AST_Sub, function(self, compressor){
|
||||||
|
var expr = self.expression;
|
||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
if (prop instanceof AST_String && compressor.option("properties")) {
|
if (compressor.option("properties")) {
|
||||||
prop = prop.getValue();
|
var key = prop.evaluate(compressor);
|
||||||
if (is_identifier_string(prop)) {
|
if (key !== prop) {
|
||||||
|
var property = "" + key;
|
||||||
|
if (is_identifier_string(property)
|
||||||
|
&& property.length <= prop.print_to_string().length + 1) {
|
||||||
return make_node(AST_Dot, self, {
|
return make_node(AST_Dot, self, {
|
||||||
expression : self.expression,
|
expression: expr,
|
||||||
property : prop
|
property: property
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
var v = parseFloat(prop);
|
if (!(prop instanceof AST_Number)) {
|
||||||
if (!isNaN(v) && v.toString() == prop) {
|
var value = parseFloat(property);
|
||||||
self.property = make_node(AST_Number, self.property, {
|
if (value.toString() == property) {
|
||||||
value: v
|
prop = self.property = make_node(AST_Number, prop, {
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
|
if (compressor.option("properties") && key !== prop) {
|
||||||
|
var node = self.flatten_object(property);
|
||||||
|
if (node) {
|
||||||
|
expr = self.expression = node.expression;
|
||||||
|
prop = self.property = node.property;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (compressor.option("properties") && compressor.option("side_effects")
|
||||||
|
&& prop instanceof AST_Number && expr instanceof AST_Array) {
|
||||||
|
var index = prop.getValue();
|
||||||
|
var elements = expr.elements;
|
||||||
|
if (index in elements) {
|
||||||
|
var flatten = true;
|
||||||
|
var values = [];
|
||||||
|
for (var i = elements.length; --i > index;) {
|
||||||
|
var value = elements[i].drop_side_effect_free(compressor);
|
||||||
|
if (value) {
|
||||||
|
values.unshift(value);
|
||||||
|
if (flatten && value.has_side_effects(compressor)) flatten = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var retValue = elements[index];
|
||||||
|
retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue;
|
||||||
|
if (!flatten) values.unshift(retValue);
|
||||||
|
while (--i >= 0) {
|
||||||
|
var value = elements[i].drop_side_effect_free(compressor);
|
||||||
|
if (value) values.unshift(value);
|
||||||
|
else index--;
|
||||||
|
}
|
||||||
|
if (flatten) {
|
||||||
|
values.push(retValue);
|
||||||
|
return make_sequence(self, values).optimize(compressor);
|
||||||
|
} else return make_node(AST_Sub, self, {
|
||||||
|
expression: make_node(AST_Array, expr, {
|
||||||
|
elements: values
|
||||||
|
}),
|
||||||
|
property: make_node(AST_Number, prop, {
|
||||||
|
value: index
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4427,25 +4622,38 @@ merge(Compressor.prototype, {
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_PropAccess.DEFMETHOD("flatten_object", function(key) {
|
||||||
|
var expr = this.expression;
|
||||||
|
if (expr instanceof AST_Object) {
|
||||||
|
var props = expr.properties;
|
||||||
|
for (var i = props.length; --i >= 0;) {
|
||||||
|
var prop = props[i];
|
||||||
|
if ("" + prop.key == key) {
|
||||||
|
if (!all(props, function(prop) {
|
||||||
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
|
})) break;
|
||||||
|
var value = prop.value;
|
||||||
|
if (value instanceof AST_Function && value.contains_this()) break;
|
||||||
|
return make_node(AST_Sub, this, {
|
||||||
|
expression: make_node(AST_Array, expr, {
|
||||||
|
elements: props.map(function(prop) {
|
||||||
|
return prop.value;
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
property: make_node(AST_Number, this, {
|
||||||
|
value: i
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor){
|
OPT(AST_Dot, function(self, compressor){
|
||||||
var def = self.resolve_defines(compressor);
|
var def = self.resolve_defines(compressor);
|
||||||
if (def) {
|
if (def) {
|
||||||
return def.optimize(compressor);
|
return def.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
|
|
||||||
var values = self.expression.properties;
|
|
||||||
for (var i = values.length; --i >= 0;) {
|
|
||||||
if (values[i].key === self.property) {
|
|
||||||
var value = values[i].value;
|
|
||||||
if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) {
|
|
||||||
var obj = self.expression.clone();
|
|
||||||
obj.properties = obj.properties.slice();
|
|
||||||
obj.properties.splice(i, 1);
|
|
||||||
return make_sequence(self, [ obj, value ]).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (compressor.option("unsafe_proto")
|
if (compressor.option("unsafe_proto")
|
||||||
&& self.expression instanceof AST_Dot
|
&& self.expression instanceof AST_Dot
|
||||||
&& self.expression.property == "prototype") {
|
&& self.expression.property == "prototype") {
|
||||||
@@ -4468,6 +4676,11 @@ merge(Compressor.prototype, {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
|
if (compressor.option("properties")) {
|
||||||
|
var node = self.flatten_object(self.property);
|
||||||
|
if (node) return node.optimize(compressor);
|
||||||
|
}
|
||||||
var ev = self.evaluate(compressor);
|
var ev = self.evaluate(compressor);
|
||||||
if (ev !== self) {
|
if (ev !== self) {
|
||||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ function minify(files, options) {
|
|||||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||||
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;
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
options.mangle = defaults(options.mangle, {
|
options.mangle = defaults(options.mangle, {
|
||||||
cache: options.nameCache && (options.nameCache.vars || {}),
|
cache: options.nameCache && (options.nameCache.vars || {}),
|
||||||
@@ -78,11 +79,16 @@ function minify(files, options) {
|
|||||||
reserved: [],
|
reserved: [],
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.nameCache && options.mangle.properties) {
|
if (options.mangle.properties) {
|
||||||
if (typeof options.mangle.properties != "object") {
|
if (typeof options.mangle.properties != "object") {
|
||||||
options.mangle.properties = {};
|
options.mangle.properties = {};
|
||||||
}
|
}
|
||||||
if (!("cache" in options.mangle.properties)) {
|
if (options.mangle.properties.keep_quoted) {
|
||||||
|
quoted_props = options.mangle.properties.reserved;
|
||||||
|
if (!Array.isArray(quoted_props)) quoted_props = [];
|
||||||
|
options.mangle.properties.reserved = quoted_props;
|
||||||
|
}
|
||||||
|
if (options.nameCache && !("cache" in options.mangle.properties)) {
|
||||||
options.mangle.properties.cache = options.nameCache.props || {};
|
options.mangle.properties.cache = options.nameCache.props || {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,6 +131,9 @@ function minify(files, options) {
|
|||||||
}
|
}
|
||||||
toplevel = options.parse.toplevel;
|
toplevel = options.parse.toplevel;
|
||||||
}
|
}
|
||||||
|
if (quoted_props) {
|
||||||
|
reserve_quoted_keys(toplevel, quoted_props);
|
||||||
|
}
|
||||||
if (options.wrap) {
|
if (options.wrap) {
|
||||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ function OutputStream(options) {
|
|||||||
case "\u2029": return "\\u2029";
|
case "\u2029": return "\\u2029";
|
||||||
case "\ufeff": return "\\ufeff";
|
case "\ufeff": return "\\ufeff";
|
||||||
case "\0":
|
case "\0":
|
||||||
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
@@ -482,13 +482,17 @@ function OutputStream(options) {
|
|||||||
nodetype.DEFMETHOD("_codegen", generator);
|
nodetype.DEFMETHOD("_codegen", generator);
|
||||||
};
|
};
|
||||||
|
|
||||||
var use_asm = false;
|
|
||||||
var in_directive = false;
|
var in_directive = false;
|
||||||
|
var active_scope = null;
|
||||||
|
var use_asm = null;
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||||
var self = this, generator = self._codegen, prev_use_asm = use_asm;
|
var self = this, generator = self._codegen;
|
||||||
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
if (self instanceof AST_Scope) {
|
||||||
use_asm = true;
|
active_scope = self;
|
||||||
|
}
|
||||||
|
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||||
|
use_asm = active_scope;
|
||||||
}
|
}
|
||||||
function doit() {
|
function doit() {
|
||||||
self.add_comments(stream);
|
self.add_comments(stream);
|
||||||
@@ -502,8 +506,8 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
stream.pop_node();
|
||||||
if (self instanceof AST_Scope) {
|
if (self === use_asm) {
|
||||||
use_asm = prev_use_asm;
|
use_asm = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||||
@@ -1109,7 +1113,7 @@ function OutputStream(options) {
|
|||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||||
return;
|
return;
|
||||||
if (self.expression instanceof AST_Lambda) {
|
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||||
output.add_mapping(self.start);
|
output.add_mapping(self.start);
|
||||||
}
|
}
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
|
|||||||
@@ -1054,6 +1054,8 @@ function parse($TEXT, options) {
|
|||||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||||
if (in_statement && !name)
|
if (in_statement && !name)
|
||||||
unexpected();
|
unexpected();
|
||||||
|
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||||
|
unexpected(prev());
|
||||||
expect("(");
|
expect("(");
|
||||||
var argnames = [];
|
var argnames = [];
|
||||||
for (var first = true; !is("punc", ")");) {
|
for (var first = true; !is("punc", ")");) {
|
||||||
|
|||||||
@@ -67,6 +67,34 @@ function find_builtins(reserved) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
|
function add(name) {
|
||||||
|
push_uniq(reserved, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||||
|
add(node.key);
|
||||||
|
} else if (node instanceof AST_Sub) {
|
||||||
|
addStrings(node.property, add);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStrings(node, add) {
|
||||||
|
node.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Sequence) {
|
||||||
|
addStrings(node.expressions[node.expressions.length - 1], add);
|
||||||
|
} else if (node instanceof AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
} else if (node instanceof AST_Conditional) {
|
||||||
|
addStrings(node.consequent, add);
|
||||||
|
addStrings(node.alternative, add);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function mangle_properties(ast, options) {
|
function mangle_properties(ast, options) {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
builtins: false,
|
builtins: false,
|
||||||
@@ -91,7 +119,6 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
var keep_quoted = options.keep_quoted;
|
|
||||||
|
|
||||||
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
||||||
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
||||||
@@ -104,12 +131,11 @@ function mangle_properties(ast, options) {
|
|||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
var unmangleable = [];
|
var unmangleable = [];
|
||||||
var to_keep = {};
|
|
||||||
|
|
||||||
// step 1: find candidates to mangle
|
// step 1: find candidates to mangle
|
||||||
ast.walk(new TreeWalker(function(node){
|
ast.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key, keep_quoted && node.quote);
|
add(node.key);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
@@ -119,14 +145,13 @@ function mangle_properties(ast, options) {
|
|||||||
add(node.property);
|
add(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, keep_quoted);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// step 2: transform the tree, renaming properties
|
// step 2: transform the tree, renaming properties
|
||||||
return ast.transform(new TreeTransformer(function(node){
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
if (!(keep_quoted && node.quote))
|
|
||||||
node.key = mangle(node.key);
|
node.key = mangle(node.key);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
@@ -136,22 +161,9 @@ function mangle_properties(ast, options) {
|
|||||||
else if (node instanceof AST_Dot) {
|
else if (node instanceof AST_Dot) {
|
||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||||
if (!keep_quoted)
|
|
||||||
node.property = mangleStrings(node.property);
|
node.property = mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
// else if (node instanceof AST_String) {
|
|
||||||
// if (should_mangle(node.value)) {
|
|
||||||
// AST_Node.warn(
|
|
||||||
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
|
|
||||||
// file : node.start.file,
|
|
||||||
// line : node.start.line,
|
|
||||||
// col : node.start.col,
|
|
||||||
// prop : node.value
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// only function declarations after this line
|
// only function declarations after this line
|
||||||
@@ -167,19 +179,13 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
if (keep_quoted && name in to_keep) return false;
|
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
return cache.props.has(name)
|
return cache.props.has(name)
|
||||||
|| names_to_mangle.indexOf(name) >= 0;
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name, keep) {
|
function add(name) {
|
||||||
if (keep) {
|
|
||||||
to_keep[name] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (can_mangle(name))
|
if (can_mangle(name))
|
||||||
push_uniq(names_to_mangle, name);
|
push_uniq(names_to_mangle, name);
|
||||||
|
|
||||||
@@ -199,19 +205,16 @@ function mangle_properties(ast, options) {
|
|||||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||||
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
||||||
|
|
||||||
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
|
if (can_mangle(debug_mangled)) {
|
||||||
mangled = debug_mangled;
|
mangled = debug_mangled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// either debug mode is off, or it is on and we could not use the mangled name
|
// either debug mode is off, or it is on and we could not use the mangled name
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
// Note: `can_mangle()` does not check if the name collides with the `to_keep` set
|
|
||||||
// (filled with quoted properties when `keep_quoted` is set). Make sure we add this
|
|
||||||
// check so we don't collide with a quoted name.
|
|
||||||
do {
|
do {
|
||||||
mangled = base54(++cache.cname);
|
mangled = base54(++cache.cname);
|
||||||
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
|
} while (!can_mangle(mangled));
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.props.set(name, mangled);
|
cache.props.set(name, mangled);
|
||||||
@@ -219,32 +222,6 @@ function mangle_properties(ast, options) {
|
|||||||
return mangled;
|
return mangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStrings(node, keep) {
|
|
||||||
var out = {};
|
|
||||||
try {
|
|
||||||
(function walk(node){
|
|
||||||
node.walk(new TreeWalker(function(node){
|
|
||||||
if (node instanceof AST_Sequence) {
|
|
||||||
walk(node.expressions[node.expressions.length - 1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_String) {
|
|
||||||
add(node.value, keep);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Conditional) {
|
|
||||||
walk(node.consequent);
|
|
||||||
walk(node.alternative);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw out;
|
|
||||||
}));
|
|
||||||
})(node);
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== out) throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mangleStrings(node) {
|
function mangleStrings(node) {
|
||||||
return node.transform(new TreeTransformer(function(node){
|
return node.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_Sequence) {
|
if (node instanceof AST_Sequence) {
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
ref.reference(options);
|
ref.reference(options);
|
||||||
});
|
});
|
||||||
node.thedef = def;
|
node.thedef = def;
|
||||||
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"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.0.26",
|
"version": "3.1.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -30,12 +30,12 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "~2.11.0",
|
"commander": "~2.11.0",
|
||||||
"source-map": "~0.5.1"
|
"source-map": "~0.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~5.1.1",
|
"acorn": "~5.1.1",
|
||||||
"mocha": "~3.4.2",
|
"mocha": "~3.5.1",
|
||||||
"semver": "~5.3.0"
|
"semver": "~5.4.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/run-tests.js"
|
"test": "node test/run-tests.js"
|
||||||
|
|||||||
@@ -128,50 +128,110 @@ constant_join_3: {
|
|||||||
|
|
||||||
for_loop: {
|
for_loop: {
|
||||||
options = {
|
options = {
|
||||||
unsafe : true,
|
evaluate: true,
|
||||||
unused : true,
|
reduce_vars: true,
|
||||||
evaluate : true,
|
unsafe: true,
|
||||||
reduce_vars : true
|
unused: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f0() {
|
function f0() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0; i < a.length; i++) {
|
var b = 0;
|
||||||
console.log(a[i]);
|
for (var i = 0; i < a.length; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function f1() {
|
function f1() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0, len = a.length; i < len; i++) {
|
var b = 0;
|
||||||
console.log(a[i]);
|
for (var i = 0, len = a.length; i < len; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function f2() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < a.length; i++) {
|
|
||||||
a[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f0() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
console.log(a[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function f1() {
|
|
||||||
var a = [1, 2, 3];
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
console.log(a[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function f2() {
|
function f2() {
|
||||||
var a = [1, 2, 3];
|
var a = [1, 2, 3];
|
||||||
for (var i = 0; i < a.length; i++)
|
for (var i = 0; i < a.length; i++)
|
||||||
a[i]++;
|
a[i]++;
|
||||||
|
return a[2];
|
||||||
}
|
}
|
||||||
|
console.log(f0(), f1(), f2());
|
||||||
}
|
}
|
||||||
|
expect: {
|
||||||
|
function f0() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
var b = 0;
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
function f1() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
var b = 0;
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
b += a[i];
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a = [1, 2, 3];
|
||||||
|
for (var i = 0; i < a.length; i++)
|
||||||
|
a[i]++;
|
||||||
|
return a[2];
|
||||||
|
}
|
||||||
|
console.log(f0(), f1(), f2());
|
||||||
|
}
|
||||||
|
expect_stdout: "6 6 4"
|
||||||
|
}
|
||||||
|
|
||||||
|
index: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a[0], a[1]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
length: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
index_length: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2 ];
|
||||||
|
console.log(a[0], a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 2);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ascii_only_true: {
|
|||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|
||||||
ascii_only_false: {
|
ascii_only_false: {
|
||||||
@@ -31,5 +31,5 @@ ascii_only_false: {
|
|||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,3 +104,65 @@ asm_mixed: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm_toplevel: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
(function(){
|
||||||
|
0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_function_expression: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
var a = function() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
return function(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_nested_functions: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
function a() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function b() {
|
||||||
|
0.0;
|
||||||
|
function c(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function d(){
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
|
||||||
|
}
|
||||||
|
|||||||
@@ -1268,22 +1268,21 @@ collapse_vars_short_circuited_conditions: {
|
|||||||
|
|
||||||
collapse_vars_regexp: {
|
collapse_vars_regexp: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
|
||||||
loops: false,
|
|
||||||
sequences: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
booleans: true,
|
||||||
unused: true,
|
cascade: true,
|
||||||
hoist_funs: true,
|
collapse_vars: true,
|
||||||
keep_fargs: true,
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
join_vars: true,
|
join_vars: true,
|
||||||
cascade: true,
|
hoist_funs: true,
|
||||||
side_effects: true,
|
keep_fargs: true,
|
||||||
|
loops: false,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f1() {
|
function f1() {
|
||||||
@@ -1292,12 +1291,12 @@ collapse_vars_regexp: {
|
|||||||
return [rx, k];
|
return [rx, k];
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var rx = /[abc123]+/;
|
var rx = /ab*/g;
|
||||||
return function(s) {
|
return function(s) {
|
||||||
return rx.exec(s);
|
return rx.exec(s);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(function(){
|
(function() {
|
||||||
var result;
|
var result;
|
||||||
var s = 'acdabcdeabbb';
|
var s = 'acdabcdeabbb';
|
||||||
var rx = /ab*/g;
|
var rx = /ab*/g;
|
||||||
@@ -1305,22 +1304,35 @@ collapse_vars_regexp: {
|
|||||||
console.log(result[0]);
|
console.log(result[0]);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
(function() {
|
||||||
|
var result;
|
||||||
|
var s = 'acdabcdeabbb';
|
||||||
|
var rx = f2();
|
||||||
|
while (result = rx(s)) {
|
||||||
|
console.log(result[0]);
|
||||||
|
}
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f1() {
|
function f1() {
|
||||||
return [/[A-Z]+/, 9];
|
return [/[A-Z]+/, 9];
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var rx = /[abc123]+/;
|
var rx = /ab*/g;
|
||||||
return function(s) {
|
return function(s) {
|
||||||
return rx.exec(s);
|
return rx.exec(s);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(function(){
|
(function() {
|
||||||
var result, rx = /ab*/g;
|
var result, rx = /ab*/g;
|
||||||
while (result = rx.exec("acdabcdeabbb"))
|
while (result = rx.exec("acdabcdeabbb"))
|
||||||
console.log(result[0]);
|
console.log(result[0]);
|
||||||
})();
|
})();
|
||||||
|
(function() {
|
||||||
|
var result, rx = f2();
|
||||||
|
while (result = rx("acdabcdeabbb"))
|
||||||
|
console.log(result[0]);
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -1834,9 +1846,9 @@ issue_1858: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(x) {
|
console.log(function(x) {
|
||||||
var a = {}, b = a.b = x;
|
var a = {}, b = a.b = 1;
|
||||||
return a.b + b;
|
return a.b + b;
|
||||||
}(1));
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
@@ -2039,7 +2051,7 @@ inner_lvalues: {
|
|||||||
console.log(null, a, b);
|
console.log(null, a, b);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a, b = 10;
|
var b = 10;
|
||||||
var a = (--b || a || 3).toString(), c = --b + -a;
|
var a = (--b || a || 3).toString(), c = --b + -a;
|
||||||
console.log(null, a, b);
|
console.log(null, a, b);
|
||||||
}
|
}
|
||||||
@@ -2342,3 +2354,598 @@ duplicate_argname: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2298: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function() {
|
||||||
|
function f() {
|
||||||
|
var a = undefined;
|
||||||
|
var undefined = a++;
|
||||||
|
try {
|
||||||
|
!function g(b) {
|
||||||
|
b[1] = "foo";
|
||||||
|
}();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
(function() {
|
||||||
|
var a = undefined;
|
||||||
|
var undefined = a++;
|
||||||
|
try {
|
||||||
|
!function(b) {
|
||||||
|
(void 0)[1] = "foo";
|
||||||
|
}();
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
if (this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
this.c && console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function a() {
|
||||||
|
a && c++;
|
||||||
|
var a = 0;
|
||||||
|
a && c++;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
!function a() {
|
||||||
|
a && c++;
|
||||||
|
var a = 0;
|
||||||
|
a && c++;
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2365: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
var b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}({ f: 1 }));
|
||||||
|
console.log(function() {
|
||||||
|
var a = { f: 1 }, b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}());
|
||||||
|
console.log({
|
||||||
|
f: 1,
|
||||||
|
g: function() {
|
||||||
|
var b = this.f;
|
||||||
|
this.f++;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}.g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
var b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}({ f: 1 }));
|
||||||
|
console.log(function() {
|
||||||
|
var a = { f: 1 }, b = a.f;
|
||||||
|
a.f++;
|
||||||
|
return b;
|
||||||
|
}());
|
||||||
|
console.log({
|
||||||
|
f: 1,
|
||||||
|
g: function() {
|
||||||
|
var b = this.f;
|
||||||
|
this.f++;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}.g());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo() {
|
||||||
|
var first = arguments[0];
|
||||||
|
var result = inc(first);
|
||||||
|
return foo.amount = first.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo() {
|
||||||
|
var first = arguments[0];
|
||||||
|
var result = inc(first);
|
||||||
|
return foo.amount = first.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function callValidate() {
|
||||||
|
var validate = compilation.validate;
|
||||||
|
var result = validate.apply(null, arguments);
|
||||||
|
return callValidate.errors = validate.errors, result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function callValidate() {
|
||||||
|
var validate = compilation.validate;
|
||||||
|
var result = validate.apply(null, arguments);
|
||||||
|
return callValidate.errors = validate.errors, result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = bar.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = bar.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar, baz) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = baz.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data, data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function inc(obj) {
|
||||||
|
return obj.count++;
|
||||||
|
}
|
||||||
|
function foo(bar, baz) {
|
||||||
|
var result = inc(bar);
|
||||||
|
return foo.amount = baz.count, result;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
var answer = foo(data, data);
|
||||||
|
console.log(foo.amount, answer);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_5: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f0(o, a, h) {
|
||||||
|
var b = 3 - a;
|
||||||
|
var obj = o;
|
||||||
|
var seven = 7;
|
||||||
|
var prop = 'run';
|
||||||
|
var t = obj[prop](b)[seven] = h;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f0(o, a, h) {
|
||||||
|
return o.run(3 - a)[7] = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_6: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.p = "FAIL";
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS"
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.p = "FAIL";
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS"
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_7: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.f();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS",
|
||||||
|
f: function() {
|
||||||
|
this.p = "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a.p;
|
||||||
|
b.f();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
p: "PASS",
|
||||||
|
f: function() {
|
||||||
|
this.p = "FAIL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(f(o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_8: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b, c) {
|
||||||
|
var d = a[b.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
}];
|
||||||
|
return c.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f({}, o, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b, c) {
|
||||||
|
var d = a[b.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
}];
|
||||||
|
return c.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f({}, o, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2364_9: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var d = a();
|
||||||
|
return b.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f(function() {
|
||||||
|
o.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}, o));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var d = a();
|
||||||
|
return b.f(d);
|
||||||
|
}
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return "FAIL";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(f(function() {
|
||||||
|
o.f = function() {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}, o));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pure_getters_chain: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function o(t, r) {
|
||||||
|
var a = t[1], s = t[2], o = t[3], i = t[5];
|
||||||
|
return a <= 23 && s <= 59 && o <= 59 && (!r || i);
|
||||||
|
}
|
||||||
|
console.log(o([ , 23, 59, 59, , 42], 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function o(t, r) {
|
||||||
|
return t[1] <= 23 && t[2] <= 59 && t[3] <= 59 && (!r || t[5]);
|
||||||
|
}
|
||||||
|
console.log(o([ , 23, 59, 59, , 42], 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = "";
|
||||||
|
var d = b ? ">" : "<";
|
||||||
|
if (a) c += "=";
|
||||||
|
return c += d;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = "";
|
||||||
|
if (a) c += "=";
|
||||||
|
return c += b ? ">" : "<";
|
||||||
|
}
|
||||||
|
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "< > =< =>"
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
var c = a + 1, d = a + 2;
|
||||||
|
return b ? c : d;
|
||||||
|
}
|
||||||
|
console.log(f(3, 0), f(4, 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
return b ? a + 1 : a + 2;
|
||||||
|
}
|
||||||
|
console.log(f(3, 0), f(4, 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "5 5"
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,3 +74,40 @@ dont_change_in_or_instanceof_expressions: {
|
|||||||
null instanceof null;
|
null instanceof null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_comparison_1: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a === a;
|
||||||
|
a !== b;
|
||||||
|
b.c === a.c;
|
||||||
|
b.c !== b.c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a == a;
|
||||||
|
a !== b;
|
||||||
|
b.c === a.c;
|
||||||
|
b.c != b.c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self_comparison_2: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {}
|
||||||
|
var o = {};
|
||||||
|
console.log(f != f, o === o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {}
|
||||||
|
var o = {};
|
||||||
|
console.log(false, true);
|
||||||
|
}
|
||||||
|
expect_stdout: "false true"
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ concat_1: {
|
|||||||
var c = 1 + x() + 2 + "boo";
|
var c = 1 + x() + 2 + "boo";
|
||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
var e = 1 + x() + 2 + "X3boo";
|
var e = 1 + x() + 2 + "X3boo";
|
||||||
var f = "\x00360\08\0";
|
var f = "\x00360\x008\0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -241,18 +241,54 @@ issue_2233_1: {
|
|||||||
Array.isArray;
|
Array.isArray;
|
||||||
Boolean;
|
Boolean;
|
||||||
console.log;
|
console.log;
|
||||||
|
Date;
|
||||||
|
decodeURI;
|
||||||
|
decodeURIComponent;
|
||||||
|
encodeURI;
|
||||||
|
encodeURIComponent;
|
||||||
Error.name;
|
Error.name;
|
||||||
|
escape;
|
||||||
|
eval;
|
||||||
|
EvalError;
|
||||||
Function.length;
|
Function.length;
|
||||||
|
isFinite;
|
||||||
|
isNaN;
|
||||||
|
JSON;
|
||||||
Math.random;
|
Math.random;
|
||||||
Number.isNaN;
|
Number.isNaN;
|
||||||
|
parseFloat;
|
||||||
|
parseInt;
|
||||||
RegExp;
|
RegExp;
|
||||||
Object.defineProperty;
|
Object.defineProperty;
|
||||||
String.fromCharCode;
|
String.fromCharCode;
|
||||||
|
RangeError;
|
||||||
|
ReferenceError;
|
||||||
|
SyntaxError;
|
||||||
|
TypeError;
|
||||||
|
unescape;
|
||||||
|
URIError;
|
||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_timeout_and_interval_symbols: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// These global symbols do not exist in the test sandbox
|
||||||
|
// and must be tested separately.
|
||||||
|
clearInterval;
|
||||||
|
clearTimeout;
|
||||||
|
setInterval;
|
||||||
|
setTimeout;
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
}
|
||||||
|
|
||||||
issue_2233_2: {
|
issue_2233_2: {
|
||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
@@ -309,3 +345,71 @@ issue_2233_3: {
|
|||||||
UndeclaredGlobal;
|
UndeclaredGlobal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_fns: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Boolean(1, 2);
|
||||||
|
decodeURI(1, 2);
|
||||||
|
decodeURIComponent(1, 2);
|
||||||
|
Date(1, 2);
|
||||||
|
encodeURI(1, 2);
|
||||||
|
encodeURIComponent(1, 2);
|
||||||
|
Error(1, 2);
|
||||||
|
escape(1, 2);
|
||||||
|
EvalError(1, 2);
|
||||||
|
isFinite(1, 2);
|
||||||
|
isNaN(1, 2);
|
||||||
|
Number(1, 2);
|
||||||
|
Object(1, 2);
|
||||||
|
parseFloat(1, 2);
|
||||||
|
parseInt(1, 2);
|
||||||
|
RangeError(1, 2);
|
||||||
|
ReferenceError(1, 2);
|
||||||
|
String(1, 2);
|
||||||
|
SyntaxError(1, 2);
|
||||||
|
TypeError(1, 2);
|
||||||
|
unescape(1, 2);
|
||||||
|
URIError(1, 2);
|
||||||
|
try {
|
||||||
|
Function(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RegExp(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Array(NaN);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
Function(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
RegExp(1, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Array(NaN);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"SyntaxError",
|
||||||
|
"SyntaxError",
|
||||||
|
"RangeError",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -751,12 +751,12 @@ issue_1583: {
|
|||||||
expect: {
|
expect: {
|
||||||
function m(t) {
|
function m(t) {
|
||||||
(function(e) {
|
(function(e) {
|
||||||
t = e();
|
t = function() {
|
||||||
})(function() {
|
|
||||||
return (function(a) {
|
return (function(a) {
|
||||||
return a;
|
return function(a) {};
|
||||||
})(function(a) {});
|
})();
|
||||||
});
|
}();
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1239,3 +1239,25 @@ issue_2226_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "3"
|
expect_stdout: "3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2288: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(o) {
|
||||||
|
for (var j = o.a, i = 0; i < 0; i++);
|
||||||
|
for (var i = 0; i < 0; i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(o) {
|
||||||
|
o.a;
|
||||||
|
for (i = 0; i < 0; i++);
|
||||||
|
for (var i = 0; i < 0; i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -386,10 +386,11 @@ unsafe_object_accessor: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_function: {
|
prop_function: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(
|
console.log(
|
||||||
@@ -402,9 +403,9 @@ unsafe_function: {
|
|||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
({a:{b:1},b:function(){}}) + 1,
|
({a:{b:1},b:function(){}}) + 1,
|
||||||
({b:function(){}}, {b:1}) + 1,
|
({b:1}) + 1,
|
||||||
({a:{b:1}}, function(){}) + 1,
|
function(){} + 1,
|
||||||
({b:function(){}}, {b:1}).b + 1
|
2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -630,10 +631,11 @@ unsafe_string_bad_index: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_prototype_function: {
|
prototype_function: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate: true,
|
||||||
unsafe : true
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = ({valueOf: 0}) < 1;
|
var a = ({valueOf: 0}) < 1;
|
||||||
@@ -652,8 +654,8 @@ unsafe_prototype_function: {
|
|||||||
var d = ({toString: 0}) + "";
|
var d = ({toString: 0}) + "";
|
||||||
var e = (({valueOf: 0}) + "")[2];
|
var e = (({valueOf: 0}) + "")[2];
|
||||||
var f = (({toString: 0}) + "")[2];
|
var f = (({toString: 0}) + "")[2];
|
||||||
var g = ({}, 0)();
|
var g = 0();
|
||||||
var h = ({}, 0)();
|
var h = 0();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,6 +1023,7 @@ issue_1964_1: {
|
|||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
@@ -1028,11 +1031,15 @@ issue_1964_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect_stdout: "b"
|
expect_stdout: [
|
||||||
|
"\\s",
|
||||||
|
"b",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1964_2: {
|
issue_1964_2: {
|
||||||
@@ -1045,17 +1052,22 @@ issue_1964_2: {
|
|||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
|
console.log(/\s/.source);
|
||||||
return "a b c".split(/\s/)[1];
|
return "a b c".split(/\s/)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect_stdout: "b"
|
expect_stdout: [
|
||||||
|
"\\s",
|
||||||
|
"b",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
array_slice_index: {
|
array_slice_index: {
|
||||||
@@ -1185,3 +1197,40 @@ issue_2231_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self_comparison_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { n: NaN };
|
||||||
|
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(false, false, true, true, "number");
|
||||||
|
}
|
||||||
|
expect_stdout: "false false true true 'number'"
|
||||||
|
}
|
||||||
|
|
||||||
|
self_comparison_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { n: NaN };
|
||||||
|
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(false, false, true, true, "number");
|
||||||
|
}
|
||||||
|
expect_stdout: "false false true true 'number'"
|
||||||
|
}
|
||||||
|
|||||||
@@ -151,13 +151,13 @@ issue_1841_2: {
|
|||||||
|
|
||||||
function_returning_constant_literal: {
|
function_returning_constant_literal: {
|
||||||
options = {
|
options = {
|
||||||
reduce_vars: true,
|
|
||||||
unsafe: true,
|
|
||||||
toplevel: true,
|
|
||||||
evaluate: true,
|
|
||||||
cascade: true,
|
|
||||||
unused: true,
|
|
||||||
inline: true,
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function greeter() {
|
function greeter() {
|
||||||
|
|||||||
371
test/compress/hoist_props.js
Normal file
371
test/compress/hoist_props.js
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
issue_2377_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj_foo = 1, obj_cube = function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
};
|
||||||
|
console.log(obj_foo, obj_cube(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
}(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 27);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_1: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in obj) a++;
|
||||||
|
console.log(a, obj.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in obj) a++;
|
||||||
|
console.log(a, obj.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_2: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
var f = function(k) {
|
||||||
|
if (o[k]) return "PASS";
|
||||||
|
};
|
||||||
|
console.log(f("a"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
console.log(function(k) {
|
||||||
|
if (o[k]) return "PASS";
|
||||||
|
}("a"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access_3: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
o.b;
|
||||||
|
console.log(o.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
o.b;
|
||||||
|
console.log(o.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_1: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj_foo = 1;
|
||||||
|
var obj_bar = 2;
|
||||||
|
function f() {
|
||||||
|
var obj = {
|
||||||
|
foo: 3,
|
||||||
|
bar: 4,
|
||||||
|
"b-r": 5,
|
||||||
|
"b+r": 6,
|
||||||
|
"b!r": 7,
|
||||||
|
};
|
||||||
|
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj_foo = 1;
|
||||||
|
var obj_bar = 2;
|
||||||
|
function f() {
|
||||||
|
var obj_foo$0 = 3,
|
||||||
|
obj_bar = 4,
|
||||||
|
obj_b_r = 5,
|
||||||
|
obj_b_r$0 = 6,
|
||||||
|
obj_b_r$1 = 7;
|
||||||
|
console.log(obj_foo, obj_foo$0, obj_bar, obj_b_r, obj_b_r$0, obj_b_r$1);
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "1 3 4 5 6 7"
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_2: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
p: 1,
|
||||||
|
0: function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
1: function(x) {
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
}, o__$0 = 2, o__$1 = 3;
|
||||||
|
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = 1,
|
||||||
|
o__ = function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
o__$2 = function(x) {
|
||||||
|
return x + 1;
|
||||||
|
},
|
||||||
|
o__$0 = 2,
|
||||||
|
o__$1 = 3;
|
||||||
|
console.log(o_p === o_p, o__(4), o__$2(5), o__$0, o__$1);
|
||||||
|
}
|
||||||
|
expect_stdout: "true 4 6 2 3"
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision_3: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
p: 1,
|
||||||
|
0: function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
1: function(x) {
|
||||||
|
return x + 1;
|
||||||
|
}
|
||||||
|
}, o__$0 = 2, o__$1 = 3;
|
||||||
|
console.log(o.p === o.p, o[0](4), o[1](5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = 1,
|
||||||
|
o__ = function(x) {
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
o__$2 = function(x) {
|
||||||
|
return x + 1;
|
||||||
|
},
|
||||||
|
o__$0 = 2,
|
||||||
|
o__$1 = 3;
|
||||||
|
console.log(o_p === o_p, o__(4), o__$2(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "true 4 6"
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 1);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 1, function() {
|
||||||
|
return this === this;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_this_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
hoist_props: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
u: function() {
|
||||||
|
return this === this;
|
||||||
|
},
|
||||||
|
p: 1
|
||||||
|
};
|
||||||
|
console.log(o.p, o.p, o.u());
|
||||||
|
}
|
||||||
|
expect_stdout: "1 1 true"
|
||||||
|
}
|
||||||
@@ -88,3 +88,24 @@ sequences_funs: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2295: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
hoist_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(o) {
|
||||||
|
var a = o.a;
|
||||||
|
if (a) return a;
|
||||||
|
var a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(o) {
|
||||||
|
var a = o.a;
|
||||||
|
if (a) return a;
|
||||||
|
a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ pure_function_calls_toplevel: {
|
|||||||
})();
|
})();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// pure top-level calls will be dropped regardless of the leading comments position
|
||||||
|
var MyClass = /*#__PURE__*//*@class*/(function(){
|
||||||
|
function MyClass() {}
|
||||||
|
MyClass.prototype.method = function() {};
|
||||||
|
return MyClass;
|
||||||
|
})();
|
||||||
|
|
||||||
// comment #__PURE__ comment
|
// comment #__PURE__ comment
|
||||||
bar(), baz(), quux();
|
bar(), baz(), quux();
|
||||||
a.b(), /* @__PURE__ */ c.d.e(), f.g();
|
a.b(), /* @__PURE__ */ c.d.e(), f.g();
|
||||||
@@ -110,10 +117,12 @@ pure_function_calls_toplevel: {
|
|||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
|
||||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
|
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:107,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:108,31]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
|
||||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,45]",
|
||||||
|
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:100,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,29 +157,29 @@ should_warn: {
|
|||||||
baz();
|
baz();
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,61]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,23]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:137,23]",
|
||||||
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
|
"WARN: Boolean || always true [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:138,23]",
|
||||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:130,8]",
|
"WARN: Condition left of || always true [test/compress/issue-1261.js:139,8]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:139,8]",
|
||||||
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
|
"WARN: Boolean && always false [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
|
"WARN: Condition always false [test/compress/issue-1261.js:140,23]",
|
||||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:132,8]",
|
"WARN: Condition left of && always false [test/compress/issue-1261.js:141,8]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:141,8]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:142,23]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:143,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,31]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:145,24]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:136,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:145,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:146,31]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:137,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:146,8]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
issue_1321_no_debug: {
|
issue_1321_no_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["a"] = 2 * x.o;
|
x["a"] = 2 * x.x;
|
||||||
console.log(x.o, x["a"]);
|
console.log(x.x, x["a"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1321_debug: {
|
issue_1321_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
|
properties: {
|
||||||
|
debug: "",
|
||||||
keep_quoted: true,
|
keep_quoted: true,
|
||||||
debug: ""
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -30,16 +34,18 @@ issue_1321_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["_$foo$_"] = 2 * x.o;
|
x["_$foo$_"] = 2 * x.x;
|
||||||
console.log(x.o, x["_$foo$_"]);
|
console.log(x.x, x["_$foo$_"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1321_with_quoted: {
|
issue_1321_with_quoted: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: false
|
properties: {
|
||||||
|
keep_quoted: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x = {};
|
var x = {};
|
||||||
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.o = 1;
|
x.x = 1;
|
||||||
x["x"] = 2 * x.o;
|
x["o"] = 2 * x.x;
|
||||||
console.log(x.o, x["x"]);
|
console.log(x.x, x["o"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
mangle_props: {
|
mangle_props: {
|
||||||
mangle_props = {}
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
undefined: 1,
|
undefined: 1,
|
||||||
@@ -54,10 +56,12 @@ mangle_props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
numeric_literal: {
|
numeric_literal: {
|
||||||
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}
|
}
|
||||||
mangle_props = {}
|
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
0: 0,
|
0: 0,
|
||||||
@@ -105,7 +109,9 @@ numeric_literal: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
identifier: {
|
identifier: {
|
||||||
mangle_props = {}
|
mangle = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
var obj = {
|
var obj = {
|
||||||
abstract: 1,
|
abstract: 1,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
dont_reuse_prop: {
|
dont_reuse_prop: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
regex: /asd/
|
properties: {
|
||||||
|
regex: /asd/,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
"aaaaaaaaaabbbbb";
|
"aaaaaaaaaabbbbb";
|
||||||
@@ -20,8 +22,10 @@ dont_reuse_prop: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unmangleable_props_should_always_be_reserved: {
|
unmangleable_props_should_always_be_reserved: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
regex: /asd/
|
properties: {
|
||||||
|
regex: /asd/,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
"aaaaaaaaaabbbbb";
|
"aaaaaaaaaabbbbb";
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
keep_properties: {
|
keep_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
};
|
properties: false,
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
}
|
}
|
||||||
@@ -12,6 +13,7 @@ keep_properties: {
|
|||||||
|
|
||||||
dot_properties: {
|
dot_properties: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -37,6 +39,7 @@ dot_properties: {
|
|||||||
|
|
||||||
dot_properties_es5: {
|
dot_properties_es5: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -61,8 +64,8 @@ dot_properties_es5: {
|
|||||||
sub_properties: {
|
sub_properties: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
properties: true
|
properties: true,
|
||||||
};
|
}
|
||||||
input: {
|
input: {
|
||||||
a[0] = 0;
|
a[0] = 0;
|
||||||
a["0"] = 1;
|
a["0"] = 1;
|
||||||
@@ -81,18 +84,18 @@ sub_properties: {
|
|||||||
a[3.14] = 3;
|
a[3.14] = 3;
|
||||||
a.if = 4;
|
a.if = 4;
|
||||||
a["foo bar"] = 5;
|
a["foo bar"] = 5;
|
||||||
a[NaN] = 6;
|
a.NaN = 6;
|
||||||
a[null] = 7;
|
a.null = 7;
|
||||||
a[void 0] = 8;
|
a[void 0] = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluate_array_length: {
|
evaluate_array_length: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
evaluate: true
|
}
|
||||||
};
|
|
||||||
input: {
|
input: {
|
||||||
a = [1, 2, 3].length;
|
a = [1, 2, 3].length;
|
||||||
a = [1, 2, 3].join()["len" + "gth"];
|
a = [1, 2, 3].join()["len" + "gth"];
|
||||||
@@ -109,10 +112,10 @@ evaluate_array_length: {
|
|||||||
|
|
||||||
evaluate_string_length: {
|
evaluate_string_length: {
|
||||||
options = {
|
options = {
|
||||||
|
evaluate: true,
|
||||||
properties: true,
|
properties: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
evaluate: true
|
}
|
||||||
};
|
|
||||||
input: {
|
input: {
|
||||||
a = "foo".length;
|
a = "foo".length;
|
||||||
a = ("foo" + "bar")["len" + "gth"];
|
a = ("foo" + "bar")["len" + "gth"];
|
||||||
@@ -128,9 +131,11 @@ evaluate_string_length: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_properties: {
|
mangle_properties: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: false
|
properties: {
|
||||||
};
|
keep_quoted: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
@@ -139,20 +144,23 @@ mangle_properties: {
|
|||||||
a['run']({color: "blue", foo: "baz"});
|
a['run']({color: "blue", foo: "baz"});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
a["o"] = "bar";
|
a["a"] = "bar";
|
||||||
a.a = "red";
|
a.b = "red";
|
||||||
x = {r: 10};
|
x = {o: 10};
|
||||||
a.b(x.r, a.o);
|
a.r(x.o, a.a);
|
||||||
a['b']({a: "blue", o: "baz"});
|
a['r']({b: "blue", a: "baz"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_unquoted_properties: {
|
mangle_unquoted_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
|
properties: false,
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: false,
|
beautify: false,
|
||||||
@@ -181,24 +189,26 @@ mangle_unquoted_properties: {
|
|||||||
function f1() {
|
function f1() {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
a.o = 2;
|
a.r = 2;
|
||||||
x = {"bar": 10, f: 7};
|
x = {"bar": 10, b: 7};
|
||||||
a.f = 9;
|
a.b = 9;
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a['color'] = "red";
|
a['color'] = "red";
|
||||||
x = {bar: 10, f: 7};
|
x = {bar: 10, b: 7};
|
||||||
a.f = 9;
|
a.b = 9;
|
||||||
a.o = 3;
|
a.r = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug: {
|
mangle_debug: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: ""
|
properties: {
|
||||||
};
|
debug: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -210,9 +220,11 @@ mangle_debug: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug_true: {
|
mangle_debug_true: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: true
|
properties: {
|
||||||
};
|
debug: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -224,9 +236,11 @@ mangle_debug_true: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mangle_debug_suffix: {
|
mangle_debug_suffix: {
|
||||||
mangle_props = {
|
mangle = {
|
||||||
debug: "XYZ"
|
properties: {
|
||||||
};
|
debug: "XYZ",
|
||||||
|
},
|
||||||
|
}
|
||||||
input: {
|
input: {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
x = { baz: "ban" };
|
x = { baz: "ban" };
|
||||||
@@ -239,12 +253,15 @@ mangle_debug_suffix: {
|
|||||||
|
|
||||||
mangle_debug_suffix_keep_quoted: {
|
mangle_debug_suffix_keep_quoted: {
|
||||||
options = {
|
options = {
|
||||||
properties: false
|
evaluate: true,
|
||||||
|
properties: false,
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle = {
|
||||||
keep_quoted: true,
|
properties: {
|
||||||
debug: "XYZ",
|
debug: "XYZ",
|
||||||
reserved: []
|
keep_quoted: true,
|
||||||
|
reserved: [],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: false,
|
beautify: false,
|
||||||
@@ -665,8 +682,8 @@ accessor_this: {
|
|||||||
issue_2208_1: {
|
issue_2208_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -684,8 +701,8 @@ issue_2208_1: {
|
|||||||
issue_2208_2: {
|
issue_2208_2: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -709,8 +726,8 @@ issue_2208_2: {
|
|||||||
issue_2208_3: {
|
issue_2208_3: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
a = 42;
|
a = 42;
|
||||||
@@ -734,8 +751,8 @@ issue_2208_3: {
|
|||||||
issue_2208_4: {
|
issue_2208_4: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo() {}
|
function foo() {}
|
||||||
@@ -758,8 +775,8 @@ issue_2208_4: {
|
|||||||
issue_2208_5: {
|
issue_2208_5: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
properties: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
unsafe: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log({
|
console.log({
|
||||||
@@ -774,3 +791,218 @@ issue_2208_5: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2256: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
properties: {
|
||||||
|
keep_quoted: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({ "keep": 1 });
|
||||||
|
g.keep = g.change;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
g.keep = g.g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs_prop_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(++{
|
||||||
|
a: 1
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(++{
|
||||||
|
a: 1
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs_prop_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[1][0] = 42;
|
||||||
|
(function(a) {
|
||||||
|
a.b = "g";
|
||||||
|
})("abc");
|
||||||
|
(function(a) {
|
||||||
|
a[2] = "g";
|
||||||
|
})("def");
|
||||||
|
(function(a) {
|
||||||
|
a[""] = "g";
|
||||||
|
})("ghi");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
[1][0] = 42;
|
||||||
|
"abc".b = "g";
|
||||||
|
"def"[2] = "g";
|
||||||
|
"ghi"[""] = "g";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
literal_duplicate_key_side_effects: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
a: console.log ? "PASS" : "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(console.log ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
"": function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj[""]());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor_1: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
a: "FAIL",
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
}
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor_2: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
},
|
||||||
|
set a(v) {},
|
||||||
|
a: "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
return "PASS";
|
||||||
|
},
|
||||||
|
set a(v) {},
|
||||||
|
a: "FAIL"
|
||||||
|
}.a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
array_hole: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
[ 1, 2, , 3][1],
|
||||||
|
[ 1, 2, , 3][2],
|
||||||
|
[ 1, 2, , 3][3]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2, void 0, 3);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 undefined 3"
|
||||||
|
}
|
||||||
|
|||||||
@@ -385,3 +385,217 @@ set_mutable_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2313_1: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
return console.log(1), {
|
||||||
|
y: function() {
|
||||||
|
return console.log(2), {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++,
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
return console.log(1), {
|
||||||
|
y: function() {
|
||||||
|
return console.log(2), {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++,
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
if (x().y().z) {
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
console.log(1);
|
||||||
|
return {
|
||||||
|
y: function() {
|
||||||
|
console.log(2);
|
||||||
|
return {
|
||||||
|
z: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
x().y().z++;
|
||||||
|
x().y().z && console.log(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_5: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2313_6: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x().y++;
|
||||||
|
x().y;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x().y++;
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ unsafe_evaluate: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
reduce_vars : true,
|
reduce_vars : true,
|
||||||
|
side_effects : true,
|
||||||
unsafe : true,
|
unsafe : true,
|
||||||
unused : true
|
unused : true
|
||||||
}
|
}
|
||||||
@@ -210,7 +211,116 @@ unsafe_evaluate: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_evaluate_object: {
|
unsafe_evaluate_side_effect_free_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(){ var o={p:1}; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(o.p); return o; }());
|
||||||
|
console.log(function(){ var o={p:3}; console.log([o][0].p); return o.p; }());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(){ console.log(1); return 1; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(2); return o; }());
|
||||||
|
console.log(function(){ console.log(3); return 3; }());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_side_effect_free_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(){ var o={p:1},a=[o]; console.log(a[0].p); return o.p; }());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(){ console.log(1); return 1; }());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_escaped: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_modified: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
||||||
|
function inc() { this.p++; }
|
||||||
|
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:7}; console.log([o][0].p++); return o.p; }());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
||||||
|
function inc() { this.p++; }
|
||||||
|
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:7}; console.log([o][0].p++); return o.p; }());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_unknown: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(){ var o={p:1}; console.log(o.not_present); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(o.prototype); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3}; console.log(o.hasOwnProperty); return o.p; }());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(){ var o={p:1}; console.log(o.not_present); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:2}; console.log(o.prototype); return o.p; }());
|
||||||
|
console.log(function(){ var o={p:3}; console.log(o.hasOwnProperty); return o.p; }());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_object_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
reduce_vars : true,
|
reduce_vars : true,
|
||||||
@@ -250,7 +360,83 @@ unsafe_evaluate_object: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_evaluate_array: {
|
unsafe_evaluate_object_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(1, 2, obj.square(2), obj.cube);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_object_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
get foo() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = {
|
||||||
|
get foo() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.bar, obj.square(2), obj.cube);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_array_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
reduce_vars : true,
|
reduce_vars : true,
|
||||||
@@ -298,6 +484,132 @@ unsafe_evaluate_array: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_array_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2](2), arr[3]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(1, 2, arr[2](2), arr[3]);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_array_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++arr[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2](), arr[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++arr[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2](), arr[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2 2 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_array_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++this[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2], arr[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++this[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(1, 2, arr[2], 1);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_array_5: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++this[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2](), arr[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var arr = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
function() {
|
||||||
|
return ++this[0];
|
||||||
|
},
|
||||||
|
];
|
||||||
|
console.log(arr[0], arr[1], arr[2](), arr[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 2 2 2"
|
||||||
|
}
|
||||||
|
|
||||||
unsafe_evaluate_equality_1: {
|
unsafe_evaluate_equality_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
@@ -1189,10 +1501,10 @@ defun_label: {
|
|||||||
!function() {
|
!function() {
|
||||||
console.log(function(a) {
|
console.log(function(a) {
|
||||||
L: {
|
L: {
|
||||||
if (a) break L;
|
if (2) break L;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}(2));
|
}());
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -1898,10 +2210,7 @@ redefine_farg_3: {
|
|||||||
console.log(f([]), g([]), h([]));
|
console.log(f([]), g([]), h([]));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a) {
|
console.log(typeof [], "number", "undefined");
|
||||||
var a;
|
|
||||||
return typeof a;
|
|
||||||
}([]), "number", "undefined");
|
|
||||||
}
|
}
|
||||||
expect_stdout: "object number undefined"
|
expect_stdout: "object number undefined"
|
||||||
}
|
}
|
||||||
@@ -2549,7 +2858,7 @@ issue_1922_2: {
|
|||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
accessor: {
|
accessor_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -2578,6 +2887,33 @@ accessor: {
|
|||||||
expect_stdout: "1 1"
|
expect_stdout: "1 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accessor_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var A = 1;
|
||||||
|
var B = {
|
||||||
|
get c() {
|
||||||
|
console.log(A);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
B.c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
get c() {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
}).c;
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
for_in_prop: {
|
for_in_prop: {
|
||||||
options = {
|
options = {
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -2602,3 +2938,360 @@ for_in_prop: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj_var_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_var_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_arg_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
function f(obj) {
|
||||||
|
return obj.bar();
|
||||||
|
}
|
||||||
|
console.log(f({
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_arg_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
function f(obj) {
|
||||||
|
return obj.bar();
|
||||||
|
}
|
||||||
|
console.log(f({
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
func_arg_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
!function(a) {
|
||||||
|
console.log(a());
|
||||||
|
}(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
func_arg_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
!function(a) {
|
||||||
|
console.log(a());
|
||||||
|
}(function(a) {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(void 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
regex_loop: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
|
||||||
|
console.log(r[0]);
|
||||||
|
}
|
||||||
|
var a = /ab*/g;
|
||||||
|
f(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = /ab*/g;
|
||||||
|
(function(x) {
|
||||||
|
for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
|
||||||
|
console.log(r[0]);
|
||||||
|
})(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_for_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i = o.a--; i; i--)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = { a: 1 }.a--; i; i--)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_for_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i; i = o.a--;)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i; i = o.a--;)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
array_forin_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2, 3 ];
|
||||||
|
for (var b in a)
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
array_forin_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [];
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
a.push(b);
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = [];
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
a.push(b);
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect_stdout: "3"
|
||||||
|
}
|
||||||
|
|
||||||
|
const_expr_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2
|
||||||
|
};
|
||||||
|
o.a++;
|
||||||
|
console.log(o.a, o.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2
|
||||||
|
};
|
||||||
|
o.a++;
|
||||||
|
console.log(o.a, o.b);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
const_expr_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Object.prototype.c = function() {
|
||||||
|
this.a++;
|
||||||
|
};
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2
|
||||||
|
};
|
||||||
|
o.c();
|
||||||
|
console.log(o.a, o.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
Object.prototype.c = function() {
|
||||||
|
this.a++;
|
||||||
|
};
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2
|
||||||
|
};
|
||||||
|
o.c();
|
||||||
|
console.log(o.a, o.b);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 2"
|
||||||
|
}
|
||||||
|
|
||||||
|
escaped_prop: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = { o: { a: 1 } };
|
||||||
|
(function(o) {
|
||||||
|
o.a++;
|
||||||
|
})(obj.o);
|
||||||
|
(function(o) {
|
||||||
|
console.log(o.a);
|
||||||
|
})(obj.o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = { o: { a: 1 } };
|
||||||
|
obj.o.a++;
|
||||||
|
console.log(obj.o.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|||||||
@@ -325,3 +325,69 @@ issue_2120_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2254_1: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(s) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(e) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (t) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2254_2: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(s) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"eeeeee";
|
||||||
|
try {
|
||||||
|
console.log(f("PASS"));
|
||||||
|
} catch (e) {}
|
||||||
|
function f(t) {
|
||||||
|
try {
|
||||||
|
throw "FAIL";
|
||||||
|
} catch (e) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -739,3 +739,44 @@ issue_2062: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2313: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
a++;
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
this.c++;
|
||||||
|
if (this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0, b = 0;
|
||||||
|
var foo = {
|
||||||
|
get c() {
|
||||||
|
return a++, 42;
|
||||||
|
},
|
||||||
|
set c(c) {
|
||||||
|
b++;
|
||||||
|
},
|
||||||
|
d: function() {
|
||||||
|
if (this.c++, this.c) console.log(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo.d();
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
|
|||||||
exports["mangle_properties"] = mangle_properties;
|
exports["mangle_properties"] = mangle_properties;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["parse"] = parse;
|
exports["parse"] = parse;
|
||||||
|
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||||
exports["string_template"] = string_template;
|
exports["string_template"] = string_template;
|
||||||
exports["tokenizer"] = tokenizer;
|
exports["tokenizer"] = tokenizer;
|
||||||
exports["is_identifier"] = is_identifier;
|
exports["is_identifier"] = is_identifier;
|
||||||
|
|||||||
10
test/input/issue-2310/input.js
Normal file
10
test/input/issue-2310/input.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
function foo() {
|
||||||
|
return function() {
|
||||||
|
console.log("PASS");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var f = foo();
|
||||||
|
f();
|
||||||
|
})();
|
||||||
@@ -573,6 +573,25 @@ describe("bin/uglifyjs", function () {
|
|||||||
return JSON.stringify(map).replace(/"/g, '\\"');
|
return JSON.stringify(map).replace(/"/g, '\\"');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
it("Should include function calls in source map", function(done) {
|
||||||
|
var command = [
|
||||||
|
uglifyjscmd,
|
||||||
|
"test/input/issue-2310/input.js",
|
||||||
|
"-c",
|
||||||
|
"--source-map", "url=inline",
|
||||||
|
].join(" ");
|
||||||
|
|
||||||
|
exec(command, function(err, stdout, stderr) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
assert.strictEqual(stdout, [
|
||||||
|
'function foo(){return function(){console.log("PASS")}}foo()();',
|
||||||
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
|
||||||
|
""
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should dump AST as JSON", function(done) {
|
it("Should dump AST as JSON", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
|
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ describe("minify", function() {
|
|||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not parse invalid use of reserved words", function() {
|
||||||
|
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
|
||||||
|
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
|
||||||
|
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
||||||
|
});
|
||||||
|
|
||||||
describe("keep_quoted_props", function() {
|
describe("keep_quoted_props", function() {
|
||||||
it("Should preserve quotes in object literals", function() {
|
it("Should preserve quotes in object literals", function() {
|
||||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
@@ -124,6 +130,17 @@ describe("minify", function() {
|
|||||||
assert.strictEqual(result.code,
|
assert.strictEqual(result.code,
|
||||||
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
||||||
});
|
});
|
||||||
|
it("Should not mangle quoted property within dead code", function() {
|
||||||
|
var result = Uglify.minify('({ "keep": 1 }); g.keep = g.change;', {
|
||||||
|
mangle: {
|
||||||
|
properties: {
|
||||||
|
keep_quoted: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, "g.keep=g.g;");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("inSourceMap", function() {
|
describe("inSourceMap", function() {
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ describe("String literals", function() {
|
|||||||
var tests = [
|
var tests = [
|
||||||
['"\\76";', ';">";'],
|
['"\\76";', ';">";'],
|
||||||
['"\\0"', '"\\0";'],
|
['"\\0"', '"\\0";'],
|
||||||
['"\\08"', '"\\08";'],
|
['"\\08"', '"\\x008";'],
|
||||||
['"\\008"', '"\\08";'],
|
['"\\008"', '"\\x008";'],
|
||||||
['"\\0008"', '"\\08";'],
|
['"\\0008"', '"\\x008";'],
|
||||||
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
||||||
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
||||||
];
|
];
|
||||||
@@ -75,8 +75,8 @@ describe("String literals", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Should not throw error when digit is 8 or 9", function() {
|
it("Should not throw error when digit is 8 or 9", function() {
|
||||||
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";');
|
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
|
||||||
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";');
|
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not unescape unpaired surrogates", function() {
|
it("Should not unescape unpaired surrogates", function() {
|
||||||
|
|||||||
@@ -111,18 +111,22 @@ function run_compress_tests() {
|
|||||||
};
|
};
|
||||||
if (!options.warnings) options.warnings = true;
|
if (!options.warnings) options.warnings = true;
|
||||||
}
|
}
|
||||||
|
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
|
||||||
|
var quoted_props = test.mangle.properties.reserved;
|
||||||
|
if (!Array.isArray(quoted_props)) quoted_props = [];
|
||||||
|
test.mangle.properties.reserved = quoted_props;
|
||||||
|
U.reserve_quoted_keys(input, quoted_props);
|
||||||
|
}
|
||||||
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);
|
||||||
if (test.mangle || test.mangle_props) {
|
if (test.mangle) {
|
||||||
U.base54.reset();
|
U.base54.reset();
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
}
|
|
||||||
if (test.mangle) {
|
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
|
if (test.mangle.properties) {
|
||||||
|
output = U.mangle_properties(output, test.mangle.properties);
|
||||||
}
|
}
|
||||||
if (test.mangle_props) {
|
|
||||||
output = U.mangle_properties(output, test.mangle_props);
|
|
||||||
}
|
}
|
||||||
output = make_code(output, output_options);
|
output = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output) {
|
||||||
|
|||||||
@@ -16,11 +16,9 @@
|
|||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
"toplevel": true
|
"hoist_props": true
|
||||||
},
|
},
|
||||||
"mangle": {
|
|
||||||
"toplevel": true
|
"toplevel": true
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
|
|||||||
Reference in New Issue
Block a user