Compare commits
43 Commits
harmony-v3
...
v3.0.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3c4a8e9e7 | ||
|
|
7e164aba8f | ||
|
|
22aedef849 | ||
|
|
58fae7dc07 | ||
|
|
5bf8d7e949 | ||
|
|
1df9d06f4a | ||
|
|
3408fc9d32 | ||
|
|
eae26756f1 | ||
|
|
43add9416b | ||
|
|
efcf167e5e | ||
|
|
6ed90913ca | ||
|
|
569c21e952 | ||
|
|
87c3a2c0ce | ||
|
|
baef8bf050 | ||
|
|
0813c5316f | ||
|
|
c88139492d | ||
|
|
cb45886512 | ||
|
|
050474ab44 | ||
|
|
f6c805ae1d | ||
|
|
9464d3c20f | ||
|
|
f18abd1b9c | ||
|
|
3be06ad085 | ||
|
|
265008c948 | ||
|
|
ff526be61d | ||
|
|
e005099fb1 | ||
|
|
504a436e9d | ||
|
|
3ca902258c | ||
|
|
fd0951231c | ||
|
|
9e29b6dad2 | ||
|
|
c391576d52 | ||
|
|
ac73c5d421 | ||
|
|
547f41beba | ||
|
|
daaefc17b9 | ||
|
|
1d407e761e | ||
|
|
2b44f4ae30 | ||
|
|
e51c3541da | ||
|
|
3bf194684b | ||
|
|
aae7d49d0c | ||
|
|
0459af2ecc | ||
|
|
04f2344efc | ||
|
|
bad9d5cf88 | ||
|
|
a0f5f862df | ||
|
|
41996be86f |
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@@ -6,15 +6,15 @@
|
|||||||
|
|
||||||
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
|
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
|
||||||
|
|
||||||
**`uglify-js` version (`uglifyjs -V`)**
|
**Uglify version (`uglifyjs -V`)**
|
||||||
|
|
||||||
**JavaScript input - ideally as small as possible.**
|
**JavaScript input** <!-- ideally as small as possible -->
|
||||||
|
|
||||||
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
||||||
|
|
||||||
**JavaScript output produced and/or the error or warning.**
|
**JavaScript output or error produced.**
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Note: the release version of uglify-js only supports ES5. Those wishing
|
Note: `uglify-js` only supports ES5.
|
||||||
to minify ES6 should use the experimental harmony branch.
|
Those wishing to minify ES6 should use `uglify-es`.
|
||||||
-->
|
-->
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
before_install: "npm install -g npm"
|
|
||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.12"
|
- "0.12"
|
||||||
|
|||||||
685
README.md
685
README.md
@@ -1,15 +1,14 @@
|
|||||||
UglifyJS 3
|
UglifyJS 3
|
||||||
==========
|
==========
|
||||||
[](https://travis-ci.org/mishoo/UglifyJS2)
|
|
||||||
|
|
||||||
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
|
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
||||||
|
|
||||||
#### Note:
|
#### Note:
|
||||||
- **`uglify-js@3.x` has a new API and CLI and is not backwards compatible with [`uglify-js@2.x`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
||||||
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
||||||
- Release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
|
- `uglify-js` only supports ECMAScript 5 (ES5).
|
||||||
ES2015+ (ES6+) code then please use the [harmony](#harmony) development branch.
|
- Those wishing to minify
|
||||||
- Node 7 has a known performance regression and runs `uglify-js` twice as slow.
|
ES2015+ (ES6+) should use the `npm` package [**uglify-es**](https://github.com/mishoo/UglifyJS2/tree/harmony).
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
@@ -25,14 +24,7 @@ From NPM for programmatic use:
|
|||||||
|
|
||||||
npm install uglify-js
|
npm install uglify-js
|
||||||
|
|
||||||
From Git:
|
# Command line usage
|
||||||
|
|
||||||
git clone git://github.com/mishoo/UglifyJS2.git
|
|
||||||
cd UglifyJS2
|
|
||||||
npm link .
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
uglifyjs [input files] [options]
|
uglifyjs [input files] [options]
|
||||||
|
|
||||||
@@ -49,7 +41,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
|
|
||||||
uglifyjs --compress --mangle -- input.js
|
uglifyjs --compress --mangle -- input.js
|
||||||
|
|
||||||
The available options are:
|
### Command line options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help Print usage information.
|
-h, --help Print usage information.
|
||||||
@@ -148,23 +140,28 @@ The available options are:
|
|||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
goes to STDOUT.
|
goes to STDOUT.
|
||||||
|
|
||||||
## Source map options
|
## CLI source map options
|
||||||
|
|
||||||
UglifyJS can generate a source map file, which is highly useful for
|
UglifyJS can generate a source map file, which is highly useful for
|
||||||
debugging your compressed JavaScript. To get a source map, pass
|
debugging your compressed JavaScript. To get a source map, pass
|
||||||
`--source-map --output output.js` (source map will be written out to
|
`--source-map --output output.js` (source map will be written out to
|
||||||
`output.js.map`).
|
`output.js.map`).
|
||||||
|
|
||||||
Additionally you might need `--source-map root=<URL>` to pass the URL where
|
Additional options:
|
||||||
the original files can be found. Use `--source-map url=<URL>` to specify
|
|
||||||
the URL where the source map can be found.
|
- `--source-map filename=<NAME>` to specify the name of the source map.
|
||||||
|
|
||||||
|
- `--source-map root=<URL>` to pass the URL where the original files can be found.
|
||||||
|
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
||||||
|
`//# sourceMappingURL=` directive.
|
||||||
|
|
||||||
|
- `--source-map url=<URL>` to specify the URL where the source map can be found.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
uglifyjs /home/doe/work/foo/src/js/file1.js \
|
uglifyjs js/file1.js js/file2.js \
|
||||||
/home/doe/work/foo/src/js/file2.js \
|
|
||||||
-o foo.min.js -c -m \
|
-o foo.min.js -c -m \
|
||||||
--source-map base="/home/doe/work/foo/src",root="http://foo.com/src"
|
--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
|
||||||
@@ -183,13 +180,24 @@ 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 you need to pass `--in-source-map
|
To use this feature pass `--source-map content="/path/to/input/source.map"`
|
||||||
/path/to/input/source.map` or `--in-source-map inline` if the source map is
|
or `--source-map content=inline` if the source map is included inline with
|
||||||
included inline with the sources. Normally the input source map should also
|
the sources.
|
||||||
point to the file containing the generated JS, so if that's correct you can
|
|
||||||
omit input files from the command line.
|
|
||||||
|
|
||||||
## Mangler options
|
## CLI compress options
|
||||||
|
|
||||||
|
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
||||||
|
you can pass a comma-separated list of [compress options](#compress-options).
|
||||||
|
|
||||||
|
Options are in the form `foo=bar`, or just `foo` (the latter implies
|
||||||
|
a boolean option that you want to set `true`; it's effectively a
|
||||||
|
shortcut for `foo=true`).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
uglifyjs file.js -c toplevel,sequences=false
|
||||||
|
|
||||||
|
## CLI mangle options
|
||||||
|
|
||||||
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:
|
||||||
@@ -208,16 +216,16 @@ comma-separated list of names. For example:
|
|||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
### Mangling property names (`--mangle-props`)
|
### CLI mangling property names (`--mangle-props`)
|
||||||
|
|
||||||
**Note:** this will probably break your code. Mangling property names is a
|
**Note:** this will probably break your code. Mangling property names is a
|
||||||
separate step, different from variable name mangling. Pass
|
separate step, different from variable name mangling. Pass
|
||||||
`--mangle-props`. It will mangle all properties that are seen in some
|
`--mangle-props`. It will mangle all properties that are seen in some
|
||||||
object literal, or that are assigned to. For example:
|
object literal, or that are assigned to. For example:
|
||||||
|
|
||||||
```js
|
```javascript
|
||||||
var x = {
|
var x = {
|
||||||
foo: 1
|
foo: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
x.bar = 2;
|
x.bar = 2;
|
||||||
@@ -246,10 +254,10 @@ mangled to the same name in all of them. For this, pass `--name-cache filename.
|
|||||||
and UglifyJS will maintain these mappings in a file which can then be reused.
|
and UglifyJS will maintain these mappings in a file which can then be reused.
|
||||||
It should be initially empty. Example:
|
It should be initially empty. Example:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
rm -f /tmp/cache.json # start fresh
|
$ rm -f /tmp/cache.json # start fresh
|
||||||
uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
$ uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
||||||
uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
$ uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
||||||
@@ -258,18 +266,18 @@ of mangled property names.
|
|||||||
Using the name cache is not necessary if you compress all your files in a
|
Using the name cache is not necessary if you compress all your files in a
|
||||||
single call to UglifyJS.
|
single call to UglifyJS.
|
||||||
|
|
||||||
#### Mangling unquoted names (`--mangle-props keep_quoted`)
|
### Mangling unquoted names (`--mangle-props keep_quoted`)
|
||||||
|
|
||||||
Using quoted property name (`o["foo"]`) reserves the property name (`foo`)
|
Using quoted property name (`o["foo"]`) reserves the property name (`foo`)
|
||||||
so that it is not mangled throughout the entire script even when used in an
|
so that it is not mangled throughout the entire script even when used in an
|
||||||
unquoted style (`o.foo`). Example:
|
unquoted style (`o.foo`). Example:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
$ echo 'var o={"foo":1, bar:3}; o.foo += o.bar; console.log(o.foo);' | uglifyjs --mangle-props keep_quoted -mc
|
$ echo 'var o={"foo":1, bar:3}; o.foo += o.bar; console.log(o.foo);' | uglifyjs --mangle-props keep_quoted -mc
|
||||||
var o={foo:1,a:3};o.foo+=o.a,console.log(o.foo);
|
var o={foo:1,a:3};o.foo+=o.a,console.log(o.foo);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Debugging property name mangling
|
### Debugging property name mangling
|
||||||
|
|
||||||
You can also pass `--mangle-props debug` in order to mangle property names
|
You can also pass `--mangle-props debug` in order to mangle property names
|
||||||
without completely obscuring them. For example the property `o.foo`
|
without completely obscuring them. For example the property `o.foo`
|
||||||
@@ -284,12 +292,181 @@ random number on every compile to simulate mangling changing with different
|
|||||||
inputs (e.g. as you update the input script with new properties), and to help
|
inputs (e.g. as you update the input script with new properties), and to help
|
||||||
identify mistakes like writing mangled keys to storage.
|
identify mistakes like writing mangled keys to storage.
|
||||||
|
|
||||||
## Compressor options
|
|
||||||
|
|
||||||
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
# API Reference
|
||||||
you can pass a comma-separated list of options. Options are in the form
|
|
||||||
`foo=bar`, or just `foo` (the latter implies a boolean option that you want
|
Assuming installation via NPM, you can load UglifyJS in your application
|
||||||
to set `true`; it's effectively a shortcut for `foo=true`).
|
like this:
|
||||||
|
```javascript
|
||||||
|
var UglifyJS = require("uglify-js");
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a single high level minification function, `minify(code, options)`, which will
|
||||||
|
performs all the steps in a configurable manner.
|
||||||
|
Example:
|
||||||
|
```javascript
|
||||||
|
var code = "function add(first, second) { return first + second; }";
|
||||||
|
var result = UglifyJS.minify(code);
|
||||||
|
console.log(result.error); // runtime error, or `undefined` if no error
|
||||||
|
console.log(result.code); // minified output: function add(n,d){return n+d}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also compress multiple files:
|
||||||
|
```javascript
|
||||||
|
var code = {
|
||||||
|
"file1.js": "function add(first, second) { return first + second; }",
|
||||||
|
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||||
|
};
|
||||||
|
var result = UglifyJS.minify(code);
|
||||||
|
console.log(result.code); // function add(d,n){return d+n}console.log(add(3,7));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `toplevel` option:
|
||||||
|
```javascript
|
||||||
|
var code = {
|
||||||
|
"file1.js": "function add(first, second) { return first + second; }",
|
||||||
|
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||||
|
};
|
||||||
|
var options = { toplevel: true };
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
console.log(result.code); // console.log(function(n,o){return n+o}(3,7));
|
||||||
|
```
|
||||||
|
|
||||||
|
To produce warnings:
|
||||||
|
```javascript
|
||||||
|
var code = "function f(){ var u; return 2 + 3; }";
|
||||||
|
var options = { warnings: true };
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
console.log(result.error); // runtime error, `undefined` in this case
|
||||||
|
console.log(result.warnings); // [ 'Dropping unused variable u [0:1,18]' ]
|
||||||
|
console.log(result.code); // function f(){return 5}
|
||||||
|
```
|
||||||
|
|
||||||
|
An error example:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"foo.js" : "if (0) else console.log(1);"});
|
||||||
|
console.log(JSON.stringify(result.error));
|
||||||
|
// {"message":"Unexpected token: keyword (else)","filename":"foo.js","line":1,"col":7,"pos":7}
|
||||||
|
```
|
||||||
|
Note: unlike `uglify-js@2.x`, the `3.x` API does not throw errors. To
|
||||||
|
achieve a similar effect one could do the following:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Minify options
|
||||||
|
|
||||||
|
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||||
|
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||||
|
|
||||||
|
- `parse` (default `{}`) — pass an object if you wish to specify some
|
||||||
|
additional [parse options](#parse-options).
|
||||||
|
|
||||||
|
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
||||||
|
Pass an object to specify custom [compress options](#compress-options).
|
||||||
|
|
||||||
|
- `mangle` (default `true`) — pass `false` to skip mangling names, or pass
|
||||||
|
an object to specify [mangle options](#mangle-options) (see below).
|
||||||
|
|
||||||
|
- `mangle.properties` (default `false`) — a subcategory of the mangle option.
|
||||||
|
Pass an object to specify custom [mangle property options](#mangle-properties-options).
|
||||||
|
|
||||||
|
- `output` (default `null`) — pass an object if you wish to specify
|
||||||
|
additional [output options](#output-options). The defaults are optimized
|
||||||
|
for best compression.
|
||||||
|
|
||||||
|
- `sourceMap` (default `false`) - pass an object if you wish to specify
|
||||||
|
[source map options](#source-map-options).
|
||||||
|
|
||||||
|
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
|
||||||
|
variable and function name mangling and to drop unused variables and functions.
|
||||||
|
|
||||||
|
- `ie8` (default `false`) - set to `true` to support IE8.
|
||||||
|
|
||||||
|
## Minify options structure
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
warnings: false,
|
||||||
|
parse: {
|
||||||
|
// parse options
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
// compress options
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
// mangle options
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
// mangle property options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
// output options
|
||||||
|
},
|
||||||
|
sourceMap: {
|
||||||
|
// source map options
|
||||||
|
},
|
||||||
|
toplevel: false,
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Source map options
|
||||||
|
|
||||||
|
To generate a source map:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
||||||
|
sourceMap: {
|
||||||
|
filename: "out.js",
|
||||||
|
url: "out.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(result.code); // minified output
|
||||||
|
console.log(result.map); // source map
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the source map is not saved in a file, it's just returned in
|
||||||
|
`result.map`. The value passed for `sourceMap.url` is only used to set
|
||||||
|
`//# sourceMappingURL=out.js.map` in `result.code`. The value of
|
||||||
|
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
|
||||||
|
in source map file.
|
||||||
|
|
||||||
|
You can set option `sourceMap.url` to be `"inline"` and source map will
|
||||||
|
be appended to code.
|
||||||
|
|
||||||
|
You can also specify sourceRoot property to be included in source map:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
||||||
|
sourceMap: {
|
||||||
|
root: "http://example.com/src",
|
||||||
|
url: "out.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're compressing compiled JavaScript and have a source map for it, you
|
||||||
|
can use `sourceMap.content`:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
|
||||||
|
sourceMap: {
|
||||||
|
content: "content from compiled.js.map",
|
||||||
|
url: "minified.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// same as before, it returns `code` and `map`
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
|
||||||
|
|
||||||
|
## Parse options
|
||||||
|
|
||||||
|
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||||
|
- `html5_comments` (default `true`)
|
||||||
|
- `shebang` (default `true`) -- support `#!command` as the first line
|
||||||
|
|
||||||
|
## Compress options
|
||||||
|
|
||||||
- `sequences` (default: true) -- join consecutive simple statements using the
|
- `sequences` (default: true) -- join consecutive simple statements using the
|
||||||
comma operator. May be set to a positive integer to specify the maximum number
|
comma operator. May be set to a positive integer to specify the maximum number
|
||||||
@@ -322,6 +499,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `unsafe_proto` (default: false) -- optimize expressions like
|
- `unsafe_proto` (default: false) -- optimize expressions like
|
||||||
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
`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
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
|
|
||||||
@@ -359,8 +539,8 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
||||||
and `x = something(), x` into `x = something()`
|
and `x = something(), x` into `x = something()`
|
||||||
|
|
||||||
- `collapse_vars` -- Collapse single-use `var` and `const` definitions
|
- `collapse_vars` -- Collapse single-use non-constant variables - side
|
||||||
when possible.
|
effects permitting.
|
||||||
|
|
||||||
- `reduce_vars` -- Improve optimization on variables assigned with and
|
- `reduce_vars` -- Improve optimization on variables assigned with and
|
||||||
used as constant values.
|
used as constant values.
|
||||||
@@ -405,14 +585,146 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
compressor from discarding function names. Useful for code relying on
|
compressor from discarding function names. Useful for code relying on
|
||||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||||
|
|
||||||
- `passes` -- default `1`. Number of times to run compress. Use an
|
- `passes` -- default `1`. Number of times to run compress with a maximum of 3.
|
||||||
integer argument larger than 1 to further reduce code size in some cases.
|
In some cases more than one pass leads to further compressed code. Keep in
|
||||||
Note: raising the number of passes will increase uglify compress time.
|
mind more passes will take more time.
|
||||||
|
|
||||||
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
### The `unsafe` option
|
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
|
||||||
|
functions marked as "pure". A function call is marked as "pure" if a comment
|
||||||
|
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||||
|
example: `/*@__PURE__*/foo();`
|
||||||
|
|
||||||
|
## Mangle options
|
||||||
|
|
||||||
|
- `reserved` - pass an array of identifiers that should be excluded from mangling
|
||||||
|
|
||||||
|
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
||||||
|
default).
|
||||||
|
|
||||||
|
- `eval` — mangle names visible in scopes where eval or with are used
|
||||||
|
(disabled by default).
|
||||||
|
|
||||||
|
- `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).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// test.js
|
||||||
|
var globalVar;
|
||||||
|
function funcName(firstLongName, anotherLongName) {
|
||||||
|
var myVariable = firstLongName + anotherLongName;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
var code = fs.readFileSync("test.js", "utf8");
|
||||||
|
|
||||||
|
UglifyJS.minify(code).code;
|
||||||
|
// 'function funcName(a,n){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify(code, { mangle: { reserved: ['firstLongName'] } }).code;
|
||||||
|
// 'function funcName(firstLongName,a){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
|
||||||
|
// 'function n(n,a){}var a;'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mangle properties options
|
||||||
|
|
||||||
|
- `regex` — Pass a RegExp to only mangle certain names
|
||||||
|
- `keep_quoted` — Only mangle unquoted property names
|
||||||
|
- `debug` — Mangle names with the original name still present. Defaults to `false`.
|
||||||
|
Pass an empty string to enable, or a non-empty string to set the suffix.
|
||||||
|
|
||||||
|
## Output options
|
||||||
|
|
||||||
|
The code generator tries to output shortest code possible by default. In
|
||||||
|
case you want beautified output, pass `--beautify` (`-b`). Optionally you
|
||||||
|
can pass additional arguments that control the code output:
|
||||||
|
|
||||||
|
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
||||||
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
|
- `beautify` (default `true`) -- whether to actually beautify the output.
|
||||||
|
Passing `-b` will set this to true, but you might need to pass `-b` even
|
||||||
|
when you want to generate minified code, in order to specify additional
|
||||||
|
arguments, so you can use `-b beautify=false` to override it.
|
||||||
|
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
||||||
|
`do`, `while` or `with` statements, even if their body is a single
|
||||||
|
statement.
|
||||||
|
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||||
|
comments, `"some"` to preserve some comments, a regular expression string
|
||||||
|
(e.g. `/^!/`) or a function.
|
||||||
|
- `indent_level` (default 4)
|
||||||
|
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
||||||
|
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
||||||
|
`</script` in strings
|
||||||
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
|
quotes from property names in object literals.
|
||||||
|
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
||||||
|
- `preamble` (default `null`) -- when passed it must be a string and
|
||||||
|
it will be prepended to the output literally. The source map will
|
||||||
|
adjust for this text. Can be used to insert a comment containing
|
||||||
|
licensing information, for example.
|
||||||
|
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
||||||
|
only works if `beautify` is set to `false`.
|
||||||
|
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||||
|
objects
|
||||||
|
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
||||||
|
quoted property names and directives as well):
|
||||||
|
- `0` -- prefers double quotes, switches to single quotes when there are
|
||||||
|
more double quotes in the string itself.
|
||||||
|
- `1` -- always use single quotes
|
||||||
|
- `2` -- always use double quotes
|
||||||
|
- `3` -- always use the original quotes
|
||||||
|
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
||||||
|
you pass `false` then whenever possible we will use a newline instead of a
|
||||||
|
semicolon, leading to more readable output of uglified code (size before
|
||||||
|
gzip could be smaller; size after gzip insignificantly larger).
|
||||||
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
|
- `width` (default 80) -- only takes effect when beautification is on, this
|
||||||
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
|
obey. It refers to the width of the line text (excluding indentation).
|
||||||
|
It doesn't work very well currently, but it does make the code generated
|
||||||
|
by UglifyJS more readable.
|
||||||
|
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
||||||
|
function expressions. See
|
||||||
|
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
|
||||||
|
### Keeping copyright notices or other comments
|
||||||
|
|
||||||
|
You can pass `--comments` to retain certain comments in the output. By
|
||||||
|
default it will keep JSDoc-style comments that contain "@preserve",
|
||||||
|
"@license" or "@cc_on" (conditional compilation for IE). You can pass
|
||||||
|
`--comments all` to keep all the comments, or a valid JavaScript regexp to
|
||||||
|
keep only comments that match this regexp. For example `--comments /^!/`
|
||||||
|
will keep comments like `/*! Copyright Notice */`.
|
||||||
|
|
||||||
|
Note, however, that there might be situations where comments are lost. For
|
||||||
|
example:
|
||||||
|
```javascript
|
||||||
|
function f() {
|
||||||
|
/** @preserve Foo Bar */
|
||||||
|
function g() {
|
||||||
|
// this function is never called
|
||||||
|
}
|
||||||
|
return something();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Even though it has "@preserve", the comment will be lost because the inner
|
||||||
|
function `g` (which is the AST node to which the comment is attached to) is
|
||||||
|
discarded by the compressor as not referenced.
|
||||||
|
|
||||||
|
The safest comments where to place copyright information (or other info that
|
||||||
|
needs to be kept in the output) are comments attached to toplevel nodes.
|
||||||
|
|
||||||
|
### The `unsafe` `compress` option
|
||||||
|
|
||||||
It enables some transformations that *might* break code logic in certain
|
It enables some transformations that *might* break code logic in certain
|
||||||
contrived cases, but should be fine for most code. You might want to try it
|
contrived cases, but should be fine for most code. You might want to try it
|
||||||
@@ -436,7 +748,7 @@ scope). For example if you pass `--define DEBUG=false` then, coupled with
|
|||||||
dead code removal UglifyJS will discard the following from the output:
|
dead code removal UglifyJS will discard the following from the output:
|
||||||
```javascript
|
```javascript
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
console.log("debug stuff");
|
console.log("debug stuff");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -450,8 +762,8 @@ Another way of doing that is to declare your globals as constants in a
|
|||||||
separate file and include it into the build. For example you can have a
|
separate file and include it into the build. For example you can have a
|
||||||
`build/defines.js` file with the following:
|
`build/defines.js` file with the following:
|
||||||
```javascript
|
```javascript
|
||||||
const DEBUG = false;
|
var DEBUG = false;
|
||||||
const PRODUCTION = true;
|
var PRODUCTION = true;
|
||||||
// etc.
|
// etc.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -465,12 +777,13 @@ code as usual. The build will contain the `const` declarations if you use
|
|||||||
them. If you are targeting < ES6 environments which does not support `const`,
|
them. If you are targeting < ES6 environments which does not support `const`,
|
||||||
using `var` with `reduce_vars` (enabled by default) should suffice.
|
using `var` with `reduce_vars` (enabled by default) should suffice.
|
||||||
|
|
||||||
#### Conditional compilation, API
|
### Conditional compilation API
|
||||||
|
|
||||||
You can also use conditional compilation via the programmatic API. With the difference that the
|
You can also use conditional compilation via the programmatic API. With the difference that the
|
||||||
property name is `global_defs` and is a compressor property:
|
property name is `global_defs` and is a compressor property:
|
||||||
|
|
||||||
```js
|
```javascript
|
||||||
uglifyJS.minify([ "input.js"], {
|
var result = uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
|
||||||
compress: {
|
compress: {
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
global_defs: {
|
global_defs: {
|
||||||
@@ -480,84 +793,46 @@ uglifyJS.minify([ "input.js"], {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Beautifier options
|
### Using native Uglify AST with `minify()`
|
||||||
|
|
||||||
The code generator tries to output shortest code possible by default. In
|
|
||||||
case you want beautified output, pass `--beautify` (`-b`). Optionally you
|
|
||||||
can pass additional arguments that control the code 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
|
|
||||||
when you want to generate minified code, in order to specify additional
|
|
||||||
arguments, so you can use `-b beautify=false` to override it.
|
|
||||||
- `indent_level` (default 4)
|
|
||||||
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
|
||||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
|
||||||
objects
|
|
||||||
- `space_colon` (default `true`) -- insert a space after the colon signs
|
|
||||||
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
|
||||||
regexps (affects directives with non-ascii characters becoming invalid)
|
|
||||||
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
|
||||||
`</script` in strings
|
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
|
||||||
obey. It refers to the width of the line text (excluding indentation).
|
|
||||||
It doesn't work very well currently, but it does make the code generated
|
|
||||||
by UglifyJS more readable.
|
|
||||||
- `max_line_len` (default 32000) -- maximum line length (for uglified code)
|
|
||||||
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
|
||||||
`do`, `while` or `with` statements, even if their body is a single
|
|
||||||
statement.
|
|
||||||
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
|
||||||
you pass `false` then whenever possible we will use a newline instead of a
|
|
||||||
semicolon, leading to more readable output of uglified code (size before
|
|
||||||
gzip could be smaller; size after gzip insignificantly larger).
|
|
||||||
- `preamble` (default `null`) -- when passed it must be a string and
|
|
||||||
it will be prepended to the output literally. The source map will
|
|
||||||
adjust for this text. Can be used to insert a comment containing
|
|
||||||
licensing information, for example.
|
|
||||||
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
|
||||||
quoted property names and directives as well):
|
|
||||||
- `0` -- prefers double quotes, switches to single quotes when there are
|
|
||||||
more double quotes in the string itself.
|
|
||||||
- `1` -- always use single quotes
|
|
||||||
- `2` -- always use double quotes
|
|
||||||
- `3` -- always use the original quotes
|
|
||||||
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
|
||||||
quotes from property names in object literals.
|
|
||||||
- `ecma` (default `5`) -- set output printing mode. This will only change the
|
|
||||||
output in direct control of the beautifier. Non-compatible features in the
|
|
||||||
abstract syntax tree will still be outputted as is.
|
|
||||||
|
|
||||||
### Keeping copyright notices or other comments
|
|
||||||
|
|
||||||
You can pass `--comments` to retain certain comments in the output. By
|
|
||||||
default it will keep JSDoc-style comments that contain "@preserve",
|
|
||||||
"@license" or "@cc_on" (conditional compilation for IE). You can pass
|
|
||||||
`--comments all` to keep all the comments, or a valid JavaScript regexp to
|
|
||||||
keep only comments that match this regexp. For example `--comments /^!/`
|
|
||||||
will keep comments like `/*! Copyright Notice */`.
|
|
||||||
|
|
||||||
Note, however, that there might be situations where comments are lost. For
|
|
||||||
example:
|
|
||||||
```javascript
|
```javascript
|
||||||
function f() {
|
// example: parse only, produce native Uglify AST
|
||||||
/** @preserve Foo Bar */
|
|
||||||
function g() {
|
var result = UglifyJS.minify(code, {
|
||||||
// this function is never called
|
parse: {},
|
||||||
}
|
compress: false,
|
||||||
return something();
|
mangle: false,
|
||||||
}
|
output: {
|
||||||
|
ast: true,
|
||||||
|
code: false // optional - faster if false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// result.ast contains native Uglify AST
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
// example: accept native Uglify AST input and then compress and mangle
|
||||||
|
// to produce both code and native AST.
|
||||||
|
|
||||||
|
var result = UglifyJS.minify(ast, {
|
||||||
|
compress: {},
|
||||||
|
mangle: {},
|
||||||
|
output: {
|
||||||
|
ast: true,
|
||||||
|
code: true // optional - faster if false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// result.ast contains native Uglify AST
|
||||||
|
// result.code contains the minified code in string form.
|
||||||
```
|
```
|
||||||
|
|
||||||
Even though it has "@preserve", the comment will be lost because the inner
|
### Working with Uglify AST
|
||||||
function `g` (which is the AST node to which the comment is attached to) is
|
|
||||||
discarded by the compressor as not referenced.
|
|
||||||
|
|
||||||
The safest comments where to place copyright information (or other info that
|
Transversal and transformation of the native AST can be performed through
|
||||||
needs to be kept in the output) are comments attached to toplevel nodes.
|
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and
|
||||||
|
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively.
|
||||||
|
|
||||||
## Support for the SpiderMonkey AST
|
### ESTree / SpiderMonkey AST
|
||||||
|
|
||||||
UglifyJS has its own abstract syntax tree format; for
|
UglifyJS has its own abstract syntax tree format; for
|
||||||
[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
|
[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
|
||||||
@@ -585,155 +860,5 @@ Acorn is really fast (e.g. 250ms instead of 380ms on some 650K code), but
|
|||||||
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
||||||
in total it's a bit more than just using UglifyJS's own parser.
|
in total it's a bit more than just using UglifyJS's own parser.
|
||||||
|
|
||||||
API Reference
|
[acorn]: https://github.com/ternjs/acorn
|
||||||
-------------
|
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
||||||
|
|
||||||
Assuming installation via NPM, you can load UglifyJS in your application
|
|
||||||
like this:
|
|
||||||
```javascript
|
|
||||||
var UglifyJS = require("uglify-js");
|
|
||||||
```
|
|
||||||
|
|
||||||
There is a single toplevel function, `minify(files, options)`, which will
|
|
||||||
performs all the steps in a configurable manner.
|
|
||||||
Example:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify("var b = function() {};");
|
|
||||||
console.log(result.code); // minified output
|
|
||||||
console.log(result.error); // runtime error
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also compress multiple files:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({
|
|
||||||
"file1.js": "var a = function() {};",
|
|
||||||
"file2.js": "var b = function() {};"
|
|
||||||
});
|
|
||||||
console.log(result.code);
|
|
||||||
```
|
|
||||||
|
|
||||||
To generate a source map:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
|
||||||
sourceMap: {
|
|
||||||
filename: "out.js",
|
|
||||||
url: "out.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log(result.code); // minified output
|
|
||||||
console.log(result.map); // source map
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the source map is not saved in a file, it's just returned in
|
|
||||||
`result.map`. The value passed for `sourceMap.url` is only used to set
|
|
||||||
`//# sourceMappingURL=out.js.map` in `result.code`. The value of
|
|
||||||
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
|
|
||||||
in source map file.
|
|
||||||
|
|
||||||
You can set option `sourceMap.url` to be `"inline"` and source map will
|
|
||||||
be appended to code.
|
|
||||||
|
|
||||||
You can also specify sourceRoot property to be included in source map:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
|
||||||
sourceMap: {
|
|
||||||
root: "http://example.com/src",
|
|
||||||
url: "out.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're compressing compiled JavaScript and have a source map for it, you
|
|
||||||
can use `sourceMap.content`:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
|
|
||||||
sourceMap: {
|
|
||||||
content: "content from compiled.js.map",
|
|
||||||
url: "minified.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// same as before, it returns `code` and `map`
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
|
|
||||||
|
|
||||||
Other options:
|
|
||||||
|
|
||||||
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
|
||||||
|
|
||||||
- `mangle` (default `true`) — pass `false` to skip mangling names, or pass
|
|
||||||
an object to specify mangling options (see below).
|
|
||||||
|
|
||||||
- `mangleProperties` (default `false`) — pass an object to specify custom
|
|
||||||
mangle property options.
|
|
||||||
|
|
||||||
- `output` (default `null`) — pass an object if you wish to specify
|
|
||||||
additional [output options](#beautifier-options). The defaults are optimized
|
|
||||||
for best compression.
|
|
||||||
|
|
||||||
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
|
||||||
Pass an object to specify custom [compressor options](#compressor-options).
|
|
||||||
|
|
||||||
- `parse` (default {}) — pass an object if you wish to specify some
|
|
||||||
additional [parser options](#the-parser).
|
|
||||||
|
|
||||||
##### mangle
|
|
||||||
|
|
||||||
- `reserved` - pass an array of identifiers that should be excluded from mangling
|
|
||||||
|
|
||||||
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
|
||||||
default).
|
|
||||||
|
|
||||||
- `eval` — mangle names visible in scopes where eval or with are used
|
|
||||||
(disabled by default).
|
|
||||||
|
|
||||||
- `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](#compressor-options).
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
//tst.js
|
|
||||||
var globalVar;
|
|
||||||
function funcName(firstLongName, anotherLongName)
|
|
||||||
{
|
|
||||||
var myVariable = firstLongName + anotherLongName;
|
|
||||||
}
|
|
||||||
|
|
||||||
UglifyJS.minify("tst.js").code;
|
|
||||||
// 'function funcName(a,n){}var globalVar;'
|
|
||||||
|
|
||||||
UglifyJS.minify("tst.js", { mangle: { reserved: ['firstLongName'] } }).code;
|
|
||||||
// 'function funcName(firstLongName,a){}var globalVar;'
|
|
||||||
|
|
||||||
UglifyJS.minify("tst.js", { mangle: { toplevel: true } }).code;
|
|
||||||
// 'function n(n,a){}var a;'
|
|
||||||
```
|
|
||||||
|
|
||||||
##### mangle.properties options
|
|
||||||
|
|
||||||
- `regex` — Pass a RegExp to only mangle certain names
|
|
||||||
- `keep_quoted` — Only mangle unquoted property names
|
|
||||||
- `debug` — Mangle names with the original name still present. Defaults to `false`.
|
|
||||||
Pass an empty string to enable, or a non-empty string to set the suffix.
|
|
||||||
|
|
||||||
[acorn]: https://github.com/ternjs/acorn
|
|
||||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
|
||||||
|
|
||||||
#### Harmony
|
|
||||||
|
|
||||||
If you wish to use the experimental [harmony](https://github.com/mishoo/UglifyJS2/commits/harmony)
|
|
||||||
branch to minify ES2015+ (ES6+) code please use the following in your `package.json` file:
|
|
||||||
|
|
||||||
```
|
|
||||||
"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony"
|
|
||||||
```
|
|
||||||
|
|
||||||
or to directly install the experimental harmony version of uglify:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install --save-dev uglify-js@github:mishoo/UglifyJS2#harmony
|
|
||||||
```
|
|
||||||
|
|
||||||
See [#448](https://github.com/mishoo/UglifyJS2/issues/448) for additional details.
|
|
||||||
|
|||||||
12
bin/uglifyjs
12
bin/uglifyjs
@@ -21,8 +21,7 @@ var options = {
|
|||||||
compress: false,
|
compress: false,
|
||||||
mangle: false
|
mangle: false
|
||||||
};
|
};
|
||||||
program._name = info.name;
|
program.version(info.name + ' ' + info.version);
|
||||||
program.version(info.version);
|
|
||||||
program.parseArgv = program.parse;
|
program.parseArgv = program.parse;
|
||||||
program.parse = undefined;
|
program.parse = undefined;
|
||||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
||||||
@@ -193,7 +192,7 @@ function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
fatal(ex.stack);
|
fatal(ex);
|
||||||
}
|
}
|
||||||
var result = UglifyJS.minify(files, options);
|
var result = UglifyJS.minify(files, options);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
@@ -220,7 +219,7 @@ function run() {
|
|||||||
console.error("Supported options:");
|
console.error("Supported options:");
|
||||||
console.error(ex.defs);
|
console.error(ex.defs);
|
||||||
}
|
}
|
||||||
fatal(ex.stack);
|
fatal(ex);
|
||||||
} else if (program.output == "ast") {
|
} else if (program.output == "ast") {
|
||||||
console.log(JSON.stringify(result.ast, function(key, value) {
|
console.log(JSON.stringify(result.ast, function(key, value) {
|
||||||
if (skip_key(key)) return;
|
if (skip_key(key)) return;
|
||||||
@@ -263,7 +262,8 @@ function run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fatal(message) {
|
function fatal(message) {
|
||||||
console.error(message.replace(/^\S*?Error:/, "ERROR:"));
|
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:")
|
||||||
|
console.error(message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ function read_file(path, default_value) {
|
|||||||
return fs.readFileSync(path, "utf8");
|
return fs.readFileSync(path, "utf8");
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex.code == "ENOENT" && default_value != null) return default_value;
|
if (ex.code == "ENOENT" && default_value != null) return default_value;
|
||||||
fatal(ex.stack);
|
fatal(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
387
lib/ast.js
387
lib/ast.js
@@ -157,7 +157,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
|||||||
|
|
||||||
function walk_body(node, visitor) {
|
function walk_body(node, visitor) {
|
||||||
var body = node.body;
|
var body = node.body;
|
||||||
if (body instanceof AST_Node) {
|
if (body instanceof AST_Statement) {
|
||||||
body._walk(visitor);
|
body._walk(visitor);
|
||||||
}
|
}
|
||||||
else for (var i = 0, len = body.length; i < len; i++) {
|
else for (var i = 0, len = body.length; i < len; i++) {
|
||||||
@@ -284,10 +284,6 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", {
|
|||||||
}
|
}
|
||||||
}, AST_IterationStatement);
|
}, AST_IterationStatement);
|
||||||
|
|
||||||
var AST_ForOf = DEFNODE("ForOf", null, {
|
|
||||||
$documentation: "A `for ... of` statement",
|
|
||||||
}, AST_ForIn);
|
|
||||||
|
|
||||||
var AST_With = DEFNODE("With", "expression", {
|
var AST_With = DEFNODE("With", "expression", {
|
||||||
$documentation: "A `with` statement",
|
$documentation: "A `with` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
@@ -315,13 +311,6 @@ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_
|
|||||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||||
},
|
},
|
||||||
get_defun_scope: function () {
|
|
||||||
var self = this;
|
|
||||||
while (self.is_block_scope() && self.parent_scope) {
|
|
||||||
self = self.parent_scope;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||||
@@ -342,111 +331,13 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
}
|
}
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Expansion = DEFNODE("Expansion", "expression", {
|
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
|
||||||
$documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
|
|
||||||
$propdoc: {
|
|
||||||
expression: "AST_Symbol the thing to be expanded"
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
var self = this;
|
|
||||||
return visitor._visit(this, function(){
|
|
||||||
self.expression.walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_ArrowParametersOrSeq = DEFNODE("ArrowParametersOrSeq", "expressions", {
|
|
||||||
$documentation: "A set of arrow function parameters or a sequence expression. This is used because when the parser sees a \"(\" it could be the start of a seq, or the start of a parameter list of an arrow function.",
|
|
||||||
$propdoc: {
|
|
||||||
expressions: "[AST_Expression|AST_Destructuring|AST_Expansion*] array of expressions or argument names or destructurings."
|
|
||||||
},
|
|
||||||
as_params: function (croak) {
|
|
||||||
// We don't want anything which doesn't belong in a destructuring
|
|
||||||
var root = this;
|
|
||||||
return this.expressions.map(function to_fun_args(ex, _, __, default_seen_above) {
|
|
||||||
var insert_default = function(ex, default_value) {
|
|
||||||
if (default_value) {
|
|
||||||
return new AST_DefaultAssign({
|
|
||||||
start: ex.start,
|
|
||||||
left: ex,
|
|
||||||
operator: "=",
|
|
||||||
right: default_value,
|
|
||||||
end: default_value.end
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return ex;
|
|
||||||
}
|
|
||||||
if (ex instanceof AST_Object) {
|
|
||||||
return insert_default(new AST_Destructuring({
|
|
||||||
start: ex.start,
|
|
||||||
end: ex.end,
|
|
||||||
is_array: false,
|
|
||||||
names: ex.properties.map(to_fun_args)
|
|
||||||
}), default_seen_above);
|
|
||||||
} else if (ex instanceof AST_ObjectKeyVal) {
|
|
||||||
if (ex.key instanceof AST_SymbolRef) {
|
|
||||||
ex.key = to_fun_args(ex.key, 0, [ex.key]);
|
|
||||||
}
|
|
||||||
ex.value = to_fun_args(ex.value, 0, [ex.key]);
|
|
||||||
return insert_default(ex, default_seen_above);
|
|
||||||
} else if (ex instanceof AST_Hole) {
|
|
||||||
return ex;
|
|
||||||
} else if (ex instanceof AST_Destructuring) {
|
|
||||||
ex.names = ex.names.map(to_fun_args);
|
|
||||||
return insert_default(ex, default_seen_above);
|
|
||||||
} else if (ex instanceof AST_SymbolRef) {
|
|
||||||
return insert_default(new AST_SymbolFunarg({
|
|
||||||
name: ex.name,
|
|
||||||
start: ex.start,
|
|
||||||
end: ex.end
|
|
||||||
}), default_seen_above);
|
|
||||||
} else if (ex instanceof AST_Expansion) {
|
|
||||||
ex.expression = to_fun_args(ex.expression);
|
|
||||||
return insert_default(ex, default_seen_above);
|
|
||||||
} else if (ex instanceof AST_Array) {
|
|
||||||
return insert_default(new AST_Destructuring({
|
|
||||||
start: ex.start,
|
|
||||||
end: ex.end,
|
|
||||||
is_array: true,
|
|
||||||
names: ex.elements.map(to_fun_args)
|
|
||||||
}), default_seen_above);
|
|
||||||
} else if (ex instanceof AST_Assign) {
|
|
||||||
return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above);
|
|
||||||
} else if (ex instanceof AST_DefaultAssign) {
|
|
||||||
ex.left = to_fun_args(ex.left, 0, [ex.left]);
|
|
||||||
return ex;
|
|
||||||
} else {
|
|
||||||
croak("Invalid function parameter", ex.start.line, ex.start.col);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
as_expr: function() {
|
|
||||||
var exprs = this.expressions;
|
|
||||||
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
|
||||||
expressions: exprs
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator", {
|
|
||||||
$documentation: "Base class for functions",
|
$documentation: "Base class for functions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
is_generator: "[boolean] is generatorFn or not",
|
|
||||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||||
argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
|
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||||
},
|
},
|
||||||
args_as_names: function () {
|
|
||||||
var out = [];
|
|
||||||
for (var i = 0; i < this.argnames.length; i++) {
|
|
||||||
if (this.argnames[i] instanceof AST_Destructuring) {
|
|
||||||
out = out.concat(this.argnames[i].all_symbols());
|
|
||||||
} else {
|
|
||||||
out.push(this.argnames[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
if (this.name) this.name._walk(visitor);
|
if (this.name) this.name._walk(visitor);
|
||||||
@@ -467,78 +358,10 @@ var AST_Function = DEFNODE("Function", null, {
|
|||||||
$documentation: "A function expression"
|
$documentation: "A function expression"
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
var AST_Arrow = DEFNODE("Arrow", null, {
|
|
||||||
$documentation: "An ES6 Arrow function ((a) => b)"
|
|
||||||
}, AST_Lambda);
|
|
||||||
|
|
||||||
var AST_Defun = DEFNODE("Defun", null, {
|
var AST_Defun = DEFNODE("Defun", null, {
|
||||||
$documentation: "A function definition"
|
$documentation: "A function definition"
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
/* -----[ DESTRUCTURING ]----- */
|
|
||||||
var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
|
|
||||||
$documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
|
|
||||||
$propdoc: {
|
|
||||||
"names": "[AST_Node*] Array of properties or elements",
|
|
||||||
"is_array": "[Boolean] Whether the destructuring represents an object or array"
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
return visitor._visit(this, function(){
|
|
||||||
this.names.forEach(function(name){
|
|
||||||
name._walk(visitor);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
all_symbols: function() {
|
|
||||||
var out = [];
|
|
||||||
this.walk(new TreeWalker(function (node) {
|
|
||||||
if (node instanceof AST_Symbol) {
|
|
||||||
out.push(node);
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Expansion) {
|
|
||||||
out.push(node.expression);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", {
|
|
||||||
$documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
|
|
||||||
$propdoc: {
|
|
||||||
template_string: "[AST_TemplateString] The template string",
|
|
||||||
prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
this.prefix._walk(visitor);
|
|
||||||
this.template_string._walk(visitor);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var AST_TemplateString = DEFNODE("TemplateString", "segments", {
|
|
||||||
$documentation: "A template string literal",
|
|
||||||
$propdoc: {
|
|
||||||
segments: "[AST_TemplateSegment|AST_Expression]* One or more segments, starting with AST_TemplateSegment. AST_Expression may follow AST_TemplateSegment, but each AST_Expression must be followed by AST_TemplateSegment."
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
return visitor._visit(this, function(){
|
|
||||||
this.segments.forEach(function(seg, i){
|
|
||||||
if (i % 2 !== 0) {
|
|
||||||
seg._walk(visitor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", {
|
|
||||||
$documentation: "A segment of a template string literal",
|
|
||||||
$propdoc: {
|
|
||||||
value: "Content of the segment",
|
|
||||||
raw: "Raw content of the segment"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ JUMPS ]----- */
|
/* -----[ JUMPS ]----- */
|
||||||
|
|
||||||
var AST_Jump = DEFNODE("Jump", null, {
|
var AST_Jump = DEFNODE("Jump", null, {
|
||||||
@@ -658,7 +481,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
|
argname: "[AST_SymbolCatch] symbol for the exception"
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
@@ -672,10 +495,10 @@ var AST_Finally = DEFNODE("Finally", null, {
|
|||||||
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
/* -----[ VAR/CONST ]----- */
|
/* -----[ VAR ]----- */
|
||||||
|
|
||||||
var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||||
$documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
|
$documentation: "Base class for `var` nodes (variable declarations/initializations)",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
definitions: "[AST_VarDef*] array of variable definitions"
|
definitions: "[AST_VarDef*] array of variable definitions"
|
||||||
},
|
},
|
||||||
@@ -693,75 +516,10 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
$documentation: "A `var` statement"
|
$documentation: "A `var` statement"
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
|
|
||||||
var AST_Let = DEFNODE("Let", null, {
|
|
||||||
$documentation: "A `let` statement"
|
|
||||||
}, AST_Definitions);
|
|
||||||
|
|
||||||
var AST_Const = DEFNODE("Const", null, {
|
|
||||||
$documentation: "A `const` statement"
|
|
||||||
}, AST_Definitions);
|
|
||||||
|
|
||||||
var AST_NameImport = DEFNODE("NameImport", "foreign_name name", {
|
|
||||||
$documentation: "The part of the import statement that imports names from a module.",
|
|
||||||
$propdoc: {
|
|
||||||
foreign_name: "[AST_SymbolImportForeign] The name being imported (as specified in the module)",
|
|
||||||
name: "[AST_SymbolImport] The name as it becomes available to this module."
|
|
||||||
},
|
|
||||||
_walk: function (visitor) {
|
|
||||||
return visitor._visit(this, function() {
|
|
||||||
this.foreign_name._walk(visitor);
|
|
||||||
this.name._walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
|
|
||||||
$documentation: "An `import` statement",
|
|
||||||
$propdoc: {
|
|
||||||
imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
|
|
||||||
imported_names: "[AST_NameImport*] The names of non-default imported variables",
|
|
||||||
module_name: "[AST_String] String literal describing where this module came from",
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
return visitor._visit(this, function() {
|
|
||||||
if (this.imported_name) {
|
|
||||||
this.imported_name._walk(visitor);
|
|
||||||
}
|
|
||||||
if (this.imported_names) {
|
|
||||||
this.imported_names.forEach(function (name_import) {
|
|
||||||
name_import._walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.module_name._walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
|
|
||||||
$documentation: "An `export` statement",
|
|
||||||
$propdoc: {
|
|
||||||
exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
|
|
||||||
exported_value: "[AST_Node?] An exported value",
|
|
||||||
exported_names: "[AST_NameImport*?] List of exported names",
|
|
||||||
module_name: "[AST_String?] Name of the file to load exports from",
|
|
||||||
is_default: "[Boolean] Whether this is the default exported value of this module"
|
|
||||||
},
|
|
||||||
_walk: function (visitor) {
|
|
||||||
visitor._visit(this, function () {
|
|
||||||
if (this.exported_definition) {
|
|
||||||
this.exported_definition._walk(visitor);
|
|
||||||
}
|
|
||||||
if (this.exported_value) {
|
|
||||||
this.exported_value._walk(visitor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, AST_Statement);
|
|
||||||
|
|
||||||
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||||
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable",
|
name: "[AST_SymbolVar] name of the variable",
|
||||||
value: "[AST_Node?] initializer, or null of there's no initializer"
|
value: "[AST_Node?] initializer, or null of there's no initializer"
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
@@ -892,10 +650,6 @@ var AST_Assign = DEFNODE("Assign", null, {
|
|||||||
$documentation: "An assignment expression — `a = b + 5`",
|
$documentation: "An assignment expression — `a = b + 5`",
|
||||||
}, AST_Binary);
|
}, AST_Binary);
|
||||||
|
|
||||||
var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
|
|
||||||
$documentation: "A default assignment expression like in `(a = 3) => a`"
|
|
||||||
}, AST_Binary);
|
|
||||||
|
|
||||||
/* -----[ LITERALS ]----- */
|
/* -----[ LITERALS ]----- */
|
||||||
|
|
||||||
var AST_Array = DEFNODE("Array", "elements", {
|
var AST_Array = DEFNODE("Array", "elements", {
|
||||||
@@ -931,13 +685,11 @@ var AST_Object = DEFNODE("Object", "properties", {
|
|||||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||||
$documentation: "Base class for literal object properties",
|
$documentation: "Base class for literal object properties",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
key: "[string|AST_Node] the property name converted to a string for ObjectKeyVal. For setters, getters and computed property this is an arbitrary AST_Node",
|
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.",
|
||||||
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
|
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
if (this.key instanceof AST_Node)
|
|
||||||
this.key._walk(visitor);
|
|
||||||
this.value._walk(visitor);
|
this.value._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -950,72 +702,21 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
|||||||
}
|
}
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", {
|
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||||
$propdoc: {
|
|
||||||
quote: "[string|undefined] the original quote character, if any",
|
|
||||||
static: "[boolean] whether this is a static setter (classes only)"
|
|
||||||
},
|
|
||||||
$documentation: "An object setter property",
|
$documentation: "An object setter property",
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", {
|
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||||
$propdoc: {
|
|
||||||
quote: "[string|undefined] the original quote character, if any",
|
|
||||||
static: "[boolean] whether this is a static getter (classes only)"
|
|
||||||
},
|
|
||||||
$documentation: "An object getter property",
|
$documentation: "An object getter property",
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator", {
|
|
||||||
$propdoc: {
|
|
||||||
quote: "[string|undefined] the original quote character, if any",
|
|
||||||
static: "[boolean] whether this method is static (classes only)",
|
|
||||||
is_generator: "[boolean] is generatorFn or not",
|
|
||||||
},
|
|
||||||
$documentation: "An ES6 concise method inside an object or class"
|
|
||||||
}, AST_ObjectProperty);
|
|
||||||
|
|
||||||
var AST_Class = DEFNODE("Class", "name extends properties", {
|
|
||||||
$propdoc: {
|
|
||||||
name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
|
|
||||||
extends: "[AST_Node]? optional parent class",
|
|
||||||
properties: "[AST_ObjectProperty*] array of properties"
|
|
||||||
},
|
|
||||||
$documentation: "An ES6 class",
|
|
||||||
_walk: function(visitor) {
|
|
||||||
return visitor._visit(this, function(){
|
|
||||||
if (this.name) {
|
|
||||||
this.name._walk(visitor);
|
|
||||||
}
|
|
||||||
if (this.extends) {
|
|
||||||
this.extends._walk(visitor);
|
|
||||||
}
|
|
||||||
this.properties.forEach(function(prop){
|
|
||||||
prop._walk(visitor);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}, AST_Scope);
|
|
||||||
|
|
||||||
var AST_DefClass = DEFNODE("DefClass", null, {
|
|
||||||
$documentation: "A class definition",
|
|
||||||
}, AST_Class);
|
|
||||||
|
|
||||||
var AST_ClassExpression = DEFNODE("ClassExpression", null, {
|
|
||||||
$documentation: "A class expression."
|
|
||||||
}, AST_Class);
|
|
||||||
|
|
||||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[string] name of this symbol",
|
name: "[string] name of this symbol",
|
||||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||||
thedef: "[SymbolDef/S] the definition of this symbol"
|
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||||
},
|
},
|
||||||
$documentation: "Base class for all symbols"
|
$documentation: "Base class for all symbols",
|
||||||
});
|
|
||||||
|
|
||||||
var AST_NewTarget = DEFNODE("NewTarget", null, {
|
|
||||||
$documentation: "A reference to new.target"
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
||||||
@@ -1023,25 +724,13 @@ var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
|||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
||||||
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
|
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
||||||
$documentation: "Symbol defining a variable",
|
$documentation: "Symbol defining a variable",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, {
|
|
||||||
$documentation: "Base class for block-scoped declaration symbols"
|
|
||||||
}, AST_SymbolDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
|
||||||
$documentation: "A constant declaration"
|
|
||||||
}, AST_SymbolBlockDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
|
|
||||||
$documentation: "A block-scoped `let` declaration"
|
|
||||||
}, AST_SymbolBlockDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
|
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
|
||||||
$documentation: "Symbol naming a function argument",
|
$documentation: "Symbol naming a function argument",
|
||||||
}, AST_SymbolVar);
|
}, AST_SymbolVar);
|
||||||
@@ -1050,33 +739,13 @@ var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
|
|||||||
$documentation: "Symbol defining a function",
|
$documentation: "Symbol defining a function",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolMethod = DEFNODE("SymbolMethod", null, {
|
|
||||||
$documentation: "Symbol in an object defining a method",
|
|
||||||
}, AST_Symbol);
|
|
||||||
|
|
||||||
var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
|
var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
|
||||||
$documentation: "Symbol naming a function expression",
|
$documentation: "Symbol naming a function expression",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
|
|
||||||
$documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
|
|
||||||
}, AST_SymbolBlockDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolClass = DEFNODE("SymbolClass", null, {
|
|
||||||
$documentation: "Symbol naming a class's name. Lexically scoped to the class."
|
|
||||||
}, AST_SymbolDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
||||||
$documentation: "Symbol naming the exception in catch",
|
$documentation: "Symbol naming the exception in catch",
|
||||||
}, AST_SymbolBlockDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
|
|
||||||
$documentation: "Symbol refering to an imported name",
|
|
||||||
}, AST_SymbolBlockDeclaration);
|
|
||||||
|
|
||||||
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
|
|
||||||
$documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
|
|
||||||
}, AST_Symbol);
|
|
||||||
|
|
||||||
var AST_Label = DEFNODE("Label", "references", {
|
var AST_Label = DEFNODE("Label", "references", {
|
||||||
$documentation: "Symbol naming a label (declaration)",
|
$documentation: "Symbol naming a label (declaration)",
|
||||||
@@ -1101,10 +770,6 @@ var AST_This = DEFNODE("This", null, {
|
|||||||
$documentation: "The `this` symbol",
|
$documentation: "The `this` symbol",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
var AST_Super = DEFNODE("Super", null, {
|
|
||||||
$documentation: "The `super` symbol",
|
|
||||||
}, AST_Symbol);
|
|
||||||
|
|
||||||
var AST_Constant = DEFNODE("Constant", null, {
|
var AST_Constant = DEFNODE("Constant", null, {
|
||||||
$documentation: "Base class for all constants",
|
$documentation: "Base class for all constants",
|
||||||
getValue: function() {
|
getValue: function() {
|
||||||
@@ -1178,21 +843,6 @@ var AST_True = DEFNODE("True", null, {
|
|||||||
value: true
|
value: true
|
||||||
}, AST_Boolean);
|
}, AST_Boolean);
|
||||||
|
|
||||||
/* -----[ Yield ]----- */
|
|
||||||
|
|
||||||
var AST_Yield = DEFNODE("Yield", "expression is_star", {
|
|
||||||
$documentation: "A `yield` statement",
|
|
||||||
$propdoc: {
|
|
||||||
expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false",
|
|
||||||
is_star: "[Boolean] Whether this is a yield or yield* statement"
|
|
||||||
},
|
|
||||||
_walk: function(visitor) {
|
|
||||||
return visitor._visit(this, this.expression && function(){
|
|
||||||
this.expression._walk(visitor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ TreeWalker ]----- */
|
/* -----[ TreeWalker ]----- */
|
||||||
|
|
||||||
function TreeWalker(callback) {
|
function TreeWalker(callback) {
|
||||||
@@ -1220,17 +870,12 @@ TreeWalker.prototype = {
|
|||||||
this.directives = Object.create(this.directives);
|
this.directives = Object.create(this.directives);
|
||||||
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
|
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
|
||||||
this.directives[node.value] = node;
|
this.directives[node.value] = node;
|
||||||
} else if (node instanceof AST_Class) {
|
|
||||||
this.directives = Object.create(this.directives);
|
|
||||||
if (!this.directives["use strict"]) {
|
|
||||||
this.directives["use strict"] = node;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.stack.push(node);
|
this.stack.push(node);
|
||||||
},
|
},
|
||||||
pop: function(node) {
|
pop: function(node) {
|
||||||
this.stack.pop();
|
this.stack.pop();
|
||||||
if (node instanceof AST_Lambda || node instanceof AST_Class) {
|
if (node instanceof AST_Lambda) {
|
||||||
this.directives = Object.getPrototypeOf(this.directives);
|
this.directives = Object.getPrototypeOf(this.directives);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1248,7 +893,7 @@ TreeWalker.prototype = {
|
|||||||
var dir = this.directives[type];
|
var dir = this.directives[type];
|
||||||
if (dir) return dir;
|
if (dir) return dir;
|
||||||
var node = this.stack[this.stack.length - 1];
|
var node = this.stack[this.stack.length - 1];
|
||||||
if (node instanceof AST_Scope && node.body) {
|
if (node instanceof AST_Scope) {
|
||||||
for (var i = 0; i < node.body.length; ++i) {
|
for (var i = 0; i < node.body.length; ++i) {
|
||||||
var st = node.body[i];
|
var st = node.body[i];
|
||||||
if (!(st instanceof AST_Directive)) break;
|
if (!(st instanceof AST_Directive)) break;
|
||||||
|
|||||||
400
lib/compress.js
400
lib/compress.js
@@ -56,7 +56,6 @@ function Compressor(options, false_by_default) {
|
|||||||
dead_code : !false_by_default,
|
dead_code : !false_by_default,
|
||||||
drop_console : false,
|
drop_console : false,
|
||||||
drop_debugger : !false_by_default,
|
drop_debugger : !false_by_default,
|
||||||
ecma : 5,
|
|
||||||
evaluate : !false_by_default,
|
evaluate : !false_by_default,
|
||||||
expression : false,
|
expression : false,
|
||||||
global_defs : {},
|
global_defs : {},
|
||||||
@@ -84,6 +83,7 @@ function Compressor(options, false_by_default) {
|
|||||||
unsafe_comps : false,
|
unsafe_comps : false,
|
||||||
unsafe_math : false,
|
unsafe_math : false,
|
||||||
unsafe_proto : false,
|
unsafe_proto : false,
|
||||||
|
unsafe_regexp : false,
|
||||||
unused : !false_by_default,
|
unused : !false_by_default,
|
||||||
warnings : false,
|
warnings : false,
|
||||||
}, true);
|
}, true);
|
||||||
@@ -298,42 +298,36 @@ merge(Compressor.prototype, {
|
|||||||
node.definition().fixed = false;
|
node.definition().fixed = false;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
if (node.name instanceof AST_Destructuring) {
|
var d = node.name.definition();
|
||||||
node.name.walk(suppressor);
|
if (d.fixed === undefined || safe_to_assign(d, node.value)) {
|
||||||
} else {
|
if (node.value) {
|
||||||
var d = node.name.definition();
|
|
||||||
if (d.fixed === undefined || safe_to_assign(d, node.value)) {
|
|
||||||
if (node.value) {
|
|
||||||
d.fixed = function() {
|
|
||||||
return node.value;
|
|
||||||
};
|
|
||||||
mark(d, false);
|
|
||||||
descend();
|
|
||||||
} else {
|
|
||||||
d.fixed = null;
|
|
||||||
}
|
|
||||||
mark(d, true);
|
|
||||||
return true;
|
|
||||||
} else if (node.value) {
|
|
||||||
d.fixed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Assign && node.operator == "=") {
|
|
||||||
if (node.left instanceof AST_Destructuring) {
|
|
||||||
node.left.walk(suppressor);
|
|
||||||
} else if (node.left instanceof AST_SymbolRef) {
|
|
||||||
var d = node.left.definition();
|
|
||||||
if (safe_to_assign(d, node.right)) {
|
|
||||||
d.references.push(node.left);
|
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.right;
|
return node.value;
|
||||||
};
|
};
|
||||||
mark(d, false);
|
mark(d, false);
|
||||||
node.right.walk(tw);
|
descend();
|
||||||
mark(d, true);
|
} else {
|
||||||
return true;
|
d.fixed = null;
|
||||||
}
|
}
|
||||||
|
mark(d, true);
|
||||||
|
return true;
|
||||||
|
} else if (node.value) {
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Assign
|
||||||
|
&& node.operator == "="
|
||||||
|
&& node.left instanceof AST_SymbolRef) {
|
||||||
|
var d = node.left.definition();
|
||||||
|
if (safe_to_assign(d, node.right)) {
|
||||||
|
d.references.push(node.left);
|
||||||
|
d.fixed = function() {
|
||||||
|
return node.right;
|
||||||
|
};
|
||||||
|
mark(d, false);
|
||||||
|
node.right.walk(tw);
|
||||||
|
mark(d, true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
@@ -361,16 +355,27 @@ merge(Compressor.prototype, {
|
|||||||
// So existing transformation rules can work on them.
|
// So existing transformation rules can work on them.
|
||||||
node.argnames.forEach(function(arg, i) {
|
node.argnames.forEach(function(arg, i) {
|
||||||
var d = arg.definition();
|
var d = arg.definition();
|
||||||
d.fixed = function() {
|
if (!node.uses_arguments && d.fixed === undefined) {
|
||||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
d.fixed = function() {
|
||||||
};
|
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||||
mark(d, true);
|
};
|
||||||
|
mark(d, true);
|
||||||
|
} else {
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
descend();
|
descend();
|
||||||
pop();
|
pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Accessor) {
|
||||||
|
var save_ids = safe_ids;
|
||||||
|
safe_ids = Object.create(null);
|
||||||
|
descend();
|
||||||
|
safe_ids = save_ids;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Binary
|
if (node instanceof AST_Binary
|
||||||
&& (node.operator == "&&" || node.operator == "||")) {
|
&& (node.operator == "&&" || node.operator == "||")) {
|
||||||
node.left.walk(tw);
|
node.left.walk(tw);
|
||||||
@@ -482,8 +487,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.fixed === false) return false;
|
if (def.fixed === false) return false;
|
||||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
||||||
return !def.orig.some(function(sym) {
|
return !def.orig.some(function(sym) {
|
||||||
return sym instanceof AST_SymbolConst
|
return sym instanceof AST_SymbolDefun
|
||||||
|| sym instanceof AST_SymbolDefun
|
|
||||||
|| sym instanceof AST_SymbolLambda;
|
|| sym instanceof AST_SymbolLambda;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -498,7 +502,9 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function reset_def(def) {
|
function reset_def(def) {
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
|
if (def.scope.uses_eval) {
|
||||||
|
def.fixed = false;
|
||||||
|
} else if (!def.global || compressor.toplevel(def)) {
|
||||||
def.fixed = undefined;
|
def.fixed = undefined;
|
||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
@@ -630,14 +636,6 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function can_be_evicted_from_block(node) {
|
|
||||||
return !(
|
|
||||||
node instanceof AST_DefClass ||
|
|
||||||
node instanceof AST_Let ||
|
|
||||||
node instanceof AST_Const
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loop_body(x) {
|
function loop_body(x) {
|
||||||
if (x instanceof AST_Switch) return x;
|
if (x instanceof AST_Switch) return x;
|
||||||
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
|
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
|
||||||
@@ -686,7 +684,7 @@ merge(Compressor.prototype, {
|
|||||||
// Will not attempt to collapse assignments into or past code blocks
|
// Will not attempt to collapse assignments into or past code blocks
|
||||||
// which are not sequentially executed, e.g. loops and conditionals.
|
// which are not sequentially executed, e.g. loops and conditionals.
|
||||||
function collapse(statements, compressor) {
|
function collapse(statements, compressor) {
|
||||||
var scope = compressor.find_parent(AST_Scope).get_defun_scope();
|
var scope = compressor.find_parent(AST_Scope);
|
||||||
if (scope.uses_eval || scope.uses_with) return statements;
|
if (scope.uses_eval || scope.uses_with) return statements;
|
||||||
var candidates = [];
|
var candidates = [];
|
||||||
var stat_index = statements.length;
|
var stat_index = statements.length;
|
||||||
@@ -714,7 +712,6 @@ merge(Compressor.prototype, {
|
|||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
||||||
|| node instanceof AST_Debugger
|
|| node instanceof AST_Debugger
|
||||||
|| node instanceof AST_Destructuring
|
|
||||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||||
|| node instanceof AST_SymbolRef && node.undeclared()
|
|| node instanceof AST_SymbolRef && node.undeclared()
|
||||||
|| node instanceof AST_Try
|
|| node instanceof AST_Try
|
||||||
@@ -799,7 +796,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
|
if (expr instanceof AST_VarDef) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
if (def.orig.length > 1
|
if (def.orig.length > 1
|
||||||
|| def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
|| def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
||||||
@@ -872,9 +869,9 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function references_in_scope(def) {
|
function references_in_scope(def) {
|
||||||
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return true;
|
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return true;
|
||||||
if (def.scope.get_defun_scope() !== scope) return false;
|
if (def.scope !== scope) return false;
|
||||||
return def.references.every(function(ref) {
|
return def.references.every(function(ref) {
|
||||||
return ref.scope.get_defun_scope() === scope;
|
return ref.scope === scope;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -882,7 +879,7 @@ merge(Compressor.prototype, {
|
|||||||
function eliminate_spurious_blocks(statements) {
|
function eliminate_spurious_blocks(statements) {
|
||||||
var seen_dirs = [];
|
var seen_dirs = [];
|
||||||
return statements.reduce(function(a, stat){
|
return statements.reduce(function(a, stat){
|
||||||
if (stat instanceof AST_BlockStatement && all(stat.body, can_be_evicted_from_block)) {
|
if (stat instanceof AST_BlockStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
||||||
} else if (stat instanceof AST_EmptyStatement) {
|
} else if (stat instanceof AST_EmptyStatement) {
|
||||||
@@ -917,12 +914,12 @@ merge(Compressor.prototype, {
|
|||||||
continue loop;
|
continue loop;
|
||||||
case stat instanceof AST_If:
|
case stat instanceof AST_If:
|
||||||
if (stat.body instanceof AST_Return) {
|
if (stat.body instanceof AST_Return) {
|
||||||
|
var value = stat.body.value;
|
||||||
//---
|
//---
|
||||||
// pretty silly case, but:
|
// pretty silly case, but:
|
||||||
// if (foo()) return; return; ==> foo(); return;
|
// if (foo()) return; return; ==> foo(); return;
|
||||||
if (((in_lambda && ret.length == 0)
|
if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value)
|
||||||
|| (ret[0] instanceof AST_Return && !ret[0].value))
|
&& !value && !stat.alternative) {
|
||||||
&& !stat.body.value && !stat.alternative) {
|
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
||||||
body: stat.condition
|
body: stat.condition
|
||||||
@@ -932,7 +929,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||||
if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
|
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0];
|
stat.alternative = ret[0];
|
||||||
@@ -942,7 +939,7 @@ merge(Compressor.prototype, {
|
|||||||
//---
|
//---
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
||||||
&& stat.body.value && !stat.alternative && in_lambda) {
|
&& value && !stat.alternative && in_lambda) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
||||||
@@ -952,8 +949,8 @@ merge(Compressor.prototype, {
|
|||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
|
// if (foo()) return [ void bar() ]; [ else x...; ] y... ==> if (!foo()) { x...; y... } else bar();
|
||||||
if (!stat.body.value && in_lambda) {
|
if (in_lambda && (!value || value instanceof AST_UnaryPrefix && value.operator == "void")) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = stat.condition.negate(compressor);
|
stat.condition = stat.condition.negate(compressor);
|
||||||
@@ -962,11 +959,12 @@ merge(Compressor.prototype, {
|
|||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
stat.alternative = null;
|
stat.alternative = value ? make_node(AST_SimpleStatement, value, {
|
||||||
|
body: value.expression
|
||||||
|
}) : null;
|
||||||
ret = funs.concat([ stat.transform(compressor) ]);
|
ret = funs.concat([ stat.transform(compressor) ]);
|
||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||||
//
|
//
|
||||||
@@ -1207,7 +1205,7 @@ merge(Compressor.prototype, {
|
|||||||
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||||
}
|
}
|
||||||
stat.walk(new TreeWalker(function(node){
|
stat.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_Var) {
|
if (node instanceof AST_Definitions) {
|
||||||
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
||||||
node.remove_initializers();
|
node.remove_initializers();
|
||||||
target.push(node);
|
target.push(node);
|
||||||
@@ -1231,12 +1229,12 @@ merge(Compressor.prototype, {
|
|||||||
&& !node.expression.has_side_effects(compressor);
|
&& !node.expression.has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// may_eq_null()
|
// may_throw_on_access()
|
||||||
// returns true if this node may evaluate to null or undefined
|
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
AST_Node.DEFMETHOD("may_eq_null", function(compressor) {
|
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
||||||
var pure_getters = compressor.option("pure_getters");
|
var pure_getters = compressor.option("pure_getters");
|
||||||
return !pure_getters || this._eq_null(pure_getters);
|
return !pure_getters || this._throw_on_access(pure_getters);
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_strict(pure_getters) {
|
function is_strict(pure_getters) {
|
||||||
@@ -1248,7 +1246,12 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Undefined, return_true);
|
def(AST_Undefined, return_true);
|
||||||
def(AST_Constant, return_false);
|
def(AST_Constant, return_false);
|
||||||
def(AST_Array, return_false);
|
def(AST_Array, return_false);
|
||||||
def(AST_Object, return_false);
|
def(AST_Object, function(pure_getters) {
|
||||||
|
if (!is_strict(pure_getters)) return false;
|
||||||
|
for (var i = this.properties.length; --i >=0;)
|
||||||
|
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
def(AST_Function, return_false);
|
def(AST_Function, return_false);
|
||||||
def(AST_UnaryPostfix, return_false);
|
def(AST_UnaryPostfix, return_false);
|
||||||
def(AST_UnaryPrefix, function() {
|
def(AST_UnaryPrefix, function() {
|
||||||
@@ -1257,33 +1260,33 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Binary, function(pure_getters) {
|
def(AST_Binary, function(pure_getters) {
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&":
|
case "&&":
|
||||||
return this.left._eq_null(pure_getters);
|
return this.left._throw_on_access(pure_getters);
|
||||||
case "||":
|
case "||":
|
||||||
return this.left._eq_null(pure_getters)
|
return this.left._throw_on_access(pure_getters)
|
||||||
&& this.right._eq_null(pure_getters);
|
&& this.right._throw_on_access(pure_getters);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def(AST_Assign, function(pure_getters) {
|
def(AST_Assign, function(pure_getters) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
&& this.right._eq_null(pure_getters);
|
&& this.right._throw_on_access(pure_getters);
|
||||||
})
|
})
|
||||||
def(AST_Conditional, function(pure_getters) {
|
def(AST_Conditional, function(pure_getters) {
|
||||||
return this.consequent._eq_null(pure_getters)
|
return this.consequent._throw_on_access(pure_getters)
|
||||||
|| this.alternative._eq_null(pure_getters);
|
|| this.alternative._throw_on_access(pure_getters);
|
||||||
})
|
})
|
||||||
def(AST_Sequence, function(pure_getters) {
|
def(AST_Sequence, function(pure_getters) {
|
||||||
return this.expressions[this.expressions.length - 1]._eq_null(pure_getters);
|
return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(pure_getters) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(pure_getters)) return false;
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._eq_null(pure_getters);
|
return !fixed || fixed._throw_on_access(pure_getters);
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("_eq_null", func);
|
node.DEFMETHOD("_throw_on_access", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
@@ -1348,9 +1351,6 @@ merge(Compressor.prototype, {
|
|||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_String, return_true);
|
def(AST_String, return_true);
|
||||||
def(AST_TemplateString, function(){
|
|
||||||
return this.segments.length === 1;
|
|
||||||
});
|
|
||||||
def(AST_UnaryPrefix, function(){
|
def(AST_UnaryPrefix, function(){
|
||||||
return this.operator == "typeof";
|
return this.operator == "typeof";
|
||||||
});
|
});
|
||||||
@@ -1522,12 +1522,6 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Lambda, function(){
|
def(AST_Lambda, function(){
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
def(AST_Arrow, function() {
|
|
||||||
throw def;
|
|
||||||
});
|
|
||||||
def(AST_Class, function() {
|
|
||||||
throw def;
|
|
||||||
});
|
|
||||||
function ev(node, compressor) {
|
function ev(node, compressor) {
|
||||||
if (!compressor) throw new Error("Compressor must be passed");
|
if (!compressor) throw new Error("Compressor must be passed");
|
||||||
|
|
||||||
@@ -1539,10 +1533,6 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Constant, function(){
|
def(AST_Constant, function(){
|
||||||
return this.getValue();
|
return this.getValue();
|
||||||
});
|
});
|
||||||
def(AST_TemplateString, function() {
|
|
||||||
if (this.segments.length !== 1) throw def;
|
|
||||||
return this.segments[0].value;
|
|
||||||
});
|
|
||||||
def(AST_Array, function(compressor){
|
def(AST_Array, function(compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
return this.elements.map(function(element) {
|
return this.elements.map(function(element) {
|
||||||
@@ -1578,8 +1568,7 @@ merge(Compressor.prototype, {
|
|||||||
case "typeof":
|
case "typeof":
|
||||||
// Function would be evaluated to an array and so typeof would
|
// Function would be evaluated to an array and so typeof would
|
||||||
// incorrectly return 'object'. Hence making is a special case.
|
// incorrectly return 'object'. Hence making is a special case.
|
||||||
if (e instanceof AST_Function ||
|
if (e instanceof AST_Function) return typeof function(){};
|
||||||
e instanceof AST_Arrow) return typeof function(){};
|
|
||||||
|
|
||||||
e = ev(e, compressor);
|
e = ev(e, compressor);
|
||||||
|
|
||||||
@@ -1605,7 +1594,6 @@ merge(Compressor.prototype, {
|
|||||||
case "^" : result = ev(left, c) ^ ev(right, c); break;
|
case "^" : result = ev(left, c) ^ ev(right, c); break;
|
||||||
case "+" : result = ev(left, c) + ev(right, c); break;
|
case "+" : result = ev(left, c) + ev(right, c); break;
|
||||||
case "*" : result = ev(left, c) * ev(right, c); break;
|
case "*" : result = ev(left, c) * ev(right, c); break;
|
||||||
case "**" : result = Math.pow(ev(left, c), ev(right, c)); break;
|
|
||||||
case "/" : result = ev(left, c) / ev(right, c); break;
|
case "/" : result = ev(left, c) / ev(right, c); break;
|
||||||
case "%" : result = ev(left, c) % ev(right, c); break;
|
case "%" : result = ev(left, c) % ev(right, c); break;
|
||||||
case "-" : result = ev(left, c) - ev(right, c); break;
|
case "-" : result = ev(left, c) - ev(right, c); break;
|
||||||
@@ -1811,8 +1799,6 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Defun, return_true);
|
def(AST_Defun, return_true);
|
||||||
def(AST_Function, return_false);
|
def(AST_Function, return_false);
|
||||||
def(AST_Class, return_false);
|
|
||||||
def(AST_DefClass, return_true);
|
|
||||||
def(AST_Binary, function(compressor){
|
def(AST_Binary, function(compressor){
|
||||||
return this.left.has_side_effects(compressor)
|
return this.left.has_side_effects(compressor)
|
||||||
|| this.right.has_side_effects(compressor);
|
|| this.right.has_side_effects(compressor);
|
||||||
@@ -1835,20 +1821,17 @@ merge(Compressor.prototype, {
|
|||||||
return any(this.properties, compressor);
|
return any(this.properties, compressor);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(compressor){
|
def(AST_ObjectProperty, function(compressor){
|
||||||
if (this.key instanceof AST_ObjectKeyVal &&
|
|
||||||
this.key.has_side_effects(compressor))
|
|
||||||
return true;
|
|
||||||
return this.value.has_side_effects(compressor);
|
return this.value.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Array, function(compressor){
|
def(AST_Array, function(compressor){
|
||||||
return any(this.elements, compressor);
|
return any(this.elements, compressor);
|
||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor){
|
def(AST_Dot, function(compressor){
|
||||||
return this.expression.may_eq_null(compressor)
|
return this.expression.may_throw_on_access(compressor)
|
||||||
|| this.expression.has_side_effects(compressor);
|
|| this.expression.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor){
|
def(AST_Sub, function(compressor){
|
||||||
return this.expression.may_eq_null(compressor)
|
return this.expression.may_throw_on_access(compressor)
|
||||||
|| this.expression.has_side_effects(compressor)
|
|| this.expression.has_side_effects(compressor)
|
||||||
|| this.property.has_side_effects(compressor);
|
|| this.property.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
@@ -1884,7 +1867,7 @@ merge(Compressor.prototype, {
|
|||||||
return all(this.properties);
|
return all(this.properties);
|
||||||
});
|
});
|
||||||
def(AST_ObjectProperty, function(){
|
def(AST_ObjectProperty, function(){
|
||||||
return !(this.key instanceof AST_Node) && this.value.is_constant_expression();
|
return this.value.is_constant_expression();
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("is_constant_expression", func);
|
node.DEFMETHOD("is_constant_expression", func);
|
||||||
@@ -1901,7 +1884,6 @@ merge(Compressor.prototype, {
|
|||||||
var n = this.body.length;
|
var n = this.body.length;
|
||||||
return n > 0 && aborts(this.body[n - 1]);
|
return n > 0 && aborts(this.body[n - 1]);
|
||||||
};
|
};
|
||||||
def(AST_Import, function(){ return null; });
|
|
||||||
def(AST_BlockStatement, block_aborts);
|
def(AST_BlockStatement, block_aborts);
|
||||||
def(AST_SwitchBranch, block_aborts);
|
def(AST_SwitchBranch, block_aborts);
|
||||||
def(AST_If, function(){
|
def(AST_If, function(){
|
||||||
@@ -1935,7 +1917,6 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Block, function(self, compressor){
|
OPT(AST_Block, function(self, compressor){
|
||||||
if (self.body instanceof AST_Node) { return self; }
|
|
||||||
self.body = tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
@@ -1943,11 +1924,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_BlockStatement, function(self, compressor){
|
OPT(AST_BlockStatement, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1:
|
case 1: return self.body[0];
|
||||||
if (can_be_evicted_from_block(self.body[0])) {
|
|
||||||
return self.body[0];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0: return make_node(AST_EmptyStatement, self);
|
case 0: return make_node(AST_EmptyStatement, self);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -1960,6 +1937,7 @@ 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"));
|
var assign_as_unused = !/keep_assign/.test(compressor.option("unused"));
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
@@ -1973,17 +1951,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var var_defs_by_id = new Dictionary();
|
var var_defs_by_id = new Dictionary();
|
||||||
var initializations = new Dictionary();
|
var initializations = new Dictionary();
|
||||||
var destructuring_value = null;
|
|
||||||
var in_definition = false;
|
|
||||||
// pass 1: find out which symbols are directly used in
|
// pass 1: find out which symbols are directly used in
|
||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
var scope = this;
|
var scope = this;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node !== self) {
|
if (node !== self) {
|
||||||
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
if (node instanceof AST_Defun) {
|
||||||
if (!drop_funcs && scope === self) {
|
if (!drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
var node_def = node.name.definition();
|
||||||
if (node_def.global && !(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
}
|
}
|
||||||
@@ -1993,31 +1969,18 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
|
var node_def = def.name.definition();
|
||||||
if (def.name instanceof AST_SymbolVar) {
|
if (def.name instanceof AST_SymbolVar) {
|
||||||
var_defs_by_id.add(def.name.definition().id, def);
|
var_defs_by_id.add(node_def.id, def);
|
||||||
}
|
}
|
||||||
if (!drop_vars) {
|
if (!drop_vars) {
|
||||||
def.name.walk(new TreeWalker(function(node) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
if (node instanceof AST_SymbolDeclaration) {
|
in_use_ids[node_def.id] = true;
|
||||||
var def = node.definition();
|
in_use.push(node_def);
|
||||||
if (def.global && !(def.id in in_use_ids)) {
|
}
|
||||||
in_use_ids[def.id] = true;
|
|
||||||
in_use.push(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
if (def.value) {
|
if (def.value) {
|
||||||
if (def.name instanceof AST_Destructuring) {
|
initializations.add(def.name.name, def.value);
|
||||||
var destructuring_cache = destructuring_value;
|
|
||||||
destructuring_value = def.value;
|
|
||||||
in_definition = true;
|
|
||||||
def.walk(tw);
|
|
||||||
in_definition = false;
|
|
||||||
destructuring_value = destructuring_cache;
|
|
||||||
} else {
|
|
||||||
initializations.add(def.name.name, def.value);
|
|
||||||
}
|
|
||||||
if (def.value.has_side_effects(compressor)) {
|
if (def.value.has_side_effects(compressor)) {
|
||||||
def.value.walk(tw);
|
def.value.walk(tw);
|
||||||
}
|
}
|
||||||
@@ -2048,41 +2011,6 @@ merge(Compressor.prototype, {
|
|||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Destructuring) {
|
|
||||||
if (!in_definition) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < node.names.length; i++) {
|
|
||||||
if (node.names[i] instanceof AST_Destructuring) {
|
|
||||||
node.names[i].walk(tw);
|
|
||||||
}
|
|
||||||
else if (node.names[i] instanceof AST_Expansion) {
|
|
||||||
if (node.names[i].expression instanceof AST_Symbol) {
|
|
||||||
initializations.add(node.names[i].expression.name, destructuring_value);
|
|
||||||
} else if (node.names[i].expression instanceof AST_Destructuring) {
|
|
||||||
node.names[i].expression.walk(tw);
|
|
||||||
} else {
|
|
||||||
throw new Error(string_template("Can't handle expansion of type: {type}", {
|
|
||||||
type: Object.getPrototypeOf(node.names[i].expression).TYPE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node.names[i] instanceof AST_Hole) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (node.names[i] instanceof AST_ObjectKeyVal && typeof node.names[i].key === "string") {
|
|
||||||
initializations.add(node.names[i].key, destructuring_value);
|
|
||||||
}
|
|
||||||
else if (node.names[i] instanceof AST_Symbol) {
|
|
||||||
initializations.add(node.names[i].name, destructuring_value);
|
|
||||||
} else {
|
|
||||||
throw new Error(string_template("Unknown destructuring element of type: {type}", {
|
|
||||||
type: Object.getPrototypeOf(node.names[i]).TYPE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
@@ -2124,18 +2052,7 @@ merge(Compressor.prototype, {
|
|||||||
var trim = !compressor.option("keep_fargs");
|
var trim = !compressor.option("keep_fargs");
|
||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (sym instanceof AST_Expansion) {
|
if (!(sym.definition().id in in_use_ids)) {
|
||||||
sym = sym.expression;
|
|
||||||
}
|
|
||||||
if (sym instanceof AST_DefaultAssign) {
|
|
||||||
sym = sym.left;
|
|
||||||
}
|
|
||||||
// Do not drop destructuring arguments.
|
|
||||||
// They constitute a type assertion, so dropping
|
|
||||||
// them would stop that TypeError which would happen
|
|
||||||
// if someone called it with an incorrectly formatted
|
|
||||||
// parameter.
|
|
||||||
if (!(sym instanceof AST_Destructuring) && !(sym.definition().id in in_use_ids)) {
|
|
||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
if (trim) {
|
||||||
a.pop();
|
a.pop();
|
||||||
@@ -2147,15 +2064,14 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||||
var keep = (node.name.definition().id in in_use_ids) || !drop_funcs && node.name.definition().global;
|
if (!(node.name.definition().id in in_use_ids)) {
|
||||||
if (!keep) {
|
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) {
|
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.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
|
||||||
@@ -2164,9 +2080,7 @@ merge(Compressor.prototype, {
|
|||||||
var side_effects = [];
|
var side_effects = [];
|
||||||
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);
|
||||||
if (def.name instanceof AST_Destructuring) return tail.push(def);
|
|
||||||
var sym = def.name.definition();
|
var sym = def.name.definition();
|
||||||
if (!drop_vars && sym.global) return tail.push(def);
|
|
||||||
if (sym.id in in_use_ids) {
|
if (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);
|
||||||
@@ -2243,13 +2157,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (assign_as_unused
|
if (drop_vars && assign_as_unused
|
||||||
&& node instanceof AST_Assign
|
&& node instanceof AST_Assign
|
||||||
&& node.operator == "="
|
&& node.operator == "="
|
||||||
&& node.left instanceof AST_SymbolRef) {
|
&& node.left instanceof AST_SymbolRef) {
|
||||||
var def = node.left.definition();
|
var def = node.left.definition();
|
||||||
if (!(def.id in in_use_ids)
|
if (!(def.id in in_use_ids)
|
||||||
&& (drop_vars || !def.global)
|
|
||||||
&& self.variables.get(def.name) === def) {
|
&& self.variables.get(def.name) === def) {
|
||||||
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
||||||
}
|
}
|
||||||
@@ -2284,12 +2197,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_BlockStatement) {
|
|
||||||
descend(node, this);
|
|
||||||
if (in_list && all(node.body, can_be_evicted_from_block)) {
|
|
||||||
return MAP.splice(node.body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Scope && node !== self)
|
if (node instanceof AST_Scope && node !== self)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
@@ -2309,12 +2216,8 @@ merge(Compressor.prototype, {
|
|||||||
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
|
||||||
var self = this;
|
var self = this;
|
||||||
if (compressor.has_directive("use asm")) return self;
|
if (compressor.has_directive("use asm")) return self;
|
||||||
// Hoisting makes no sense in an arrow func
|
|
||||||
if (!Array.isArray(self.body)) return self;
|
|
||||||
|
|
||||||
var hoist_funs = compressor.option("hoist_funs");
|
var hoist_funs = compressor.option("hoist_funs");
|
||||||
var hoist_vars = compressor.option("hoist_vars");
|
var hoist_vars = compressor.option("hoist_vars");
|
||||||
|
|
||||||
if (hoist_funs || hoist_vars) {
|
if (hoist_funs || hoist_vars) {
|
||||||
var dirs = [];
|
var dirs = [];
|
||||||
var hoisted = [];
|
var hoisted = [];
|
||||||
@@ -2343,7 +2246,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Var && hoist_vars) {
|
if (node instanceof AST_Var && hoist_vars) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
if (def.name instanceof AST_Destructuring) return;
|
|
||||||
vars.set(def.name.name, def);
|
vars.set(def.name.name, def);
|
||||||
++vars_found;
|
++vars_found;
|
||||||
});
|
});
|
||||||
@@ -2376,7 +2278,7 @@ merge(Compressor.prototype, {
|
|||||||
vars.each(function(def, name){
|
vars.each(function(def, name){
|
||||||
if (self instanceof AST_Lambda
|
if (self instanceof AST_Lambda
|
||||||
&& find_if(function(x){ return x.name == def.name.name },
|
&& find_if(function(x){ return x.name == def.name.name },
|
||||||
self.args_as_names())) {
|
self.argnames)) {
|
||||||
vars.del(name);
|
vars.del(name);
|
||||||
} else {
|
} else {
|
||||||
def = def.clone();
|
def = def.clone();
|
||||||
@@ -2482,6 +2384,7 @@ merge(Compressor.prototype, {
|
|||||||
var args = trim(this.args, compressor, first_in_statement);
|
var args = trim(this.args, compressor, first_in_statement);
|
||||||
return args && make_sequence(this, args);
|
return args && make_sequence(this, args);
|
||||||
});
|
});
|
||||||
|
def(AST_Accessor, return_null);
|
||||||
def(AST_Function, return_null);
|
def(AST_Function, return_null);
|
||||||
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);
|
||||||
@@ -2549,11 +2452,11 @@ merge(Compressor.prototype, {
|
|||||||
return values && make_sequence(this, values);
|
return values && make_sequence(this, values);
|
||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor, first_in_statement){
|
def(AST_Dot, function(compressor, first_in_statement){
|
||||||
if (this.expression.may_eq_null(compressor)) return this;
|
if (this.expression.may_throw_on_access(compressor)) return this;
|
||||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
});
|
});
|
||||||
def(AST_Sub, function(compressor, first_in_statement){
|
def(AST_Sub, function(compressor, first_in_statement){
|
||||||
if (this.expression.may_eq_null(compressor)) return this;
|
if (this.expression.may_throw_on_access(compressor)) return this;
|
||||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
|
||||||
var property = this.property.drop_side_effect_free(compressor);
|
var property = this.property.drop_side_effect_free(compressor);
|
||||||
@@ -2945,7 +2848,7 @@ merge(Compressor.prototype, {
|
|||||||
AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
|
AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
|
||||||
var reduce_vars = compressor.option("reduce_vars");
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
var assignments = this.definitions.reduce(function(a, def){
|
var assignments = this.definitions.reduce(function(a, def){
|
||||||
if (def.value && !(def.name instanceof AST_Destructuring)) {
|
if (def.value) {
|
||||||
var name = make_node(AST_SymbolRef, def.name, def.name);
|
var name = make_node(AST_SymbolRef, def.name, def.name);
|
||||||
a.push(make_node(AST_Assign, def, {
|
a.push(make_node(AST_Assign, def, {
|
||||||
operator : "=",
|
operator : "=",
|
||||||
@@ -2953,16 +2856,6 @@ merge(Compressor.prototype, {
|
|||||||
right : def.value
|
right : def.value
|
||||||
}));
|
}));
|
||||||
if (reduce_vars) name.definition().fixed = false;
|
if (reduce_vars) name.definition().fixed = false;
|
||||||
} else if (def.value) {
|
|
||||||
// Because it's a destructuring, do not turn into an assignment.
|
|
||||||
var varDef = make_node(AST_VarDef, def, {
|
|
||||||
name: def.name,
|
|
||||||
value: def.value
|
|
||||||
});
|
|
||||||
var var_ = make_node(AST_Var, def, {
|
|
||||||
definitions: [ varDef ]
|
|
||||||
});
|
|
||||||
a.push(var_);
|
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
@@ -2976,10 +2869,6 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Import, function(self, compressor) {
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor){
|
OPT(AST_Call, function(self, compressor){
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (compressor.option("reduce_vars")
|
if (compressor.option("reduce_vars")
|
||||||
@@ -3105,7 +2994,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!fun) return self;
|
if (!fun) return self;
|
||||||
var args = fun.argnames.map(function(arg, i){
|
var args = fun.argnames.map(function(arg, i){
|
||||||
return make_node(AST_String, self.args[i], {
|
return make_node(AST_String, self.args[i], {
|
||||||
value: arg.print_to_string({ecma: compressor.option("ecma")})
|
value: arg.print_to_string()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var code = OutputStream();
|
var code = OutputStream();
|
||||||
@@ -3127,11 +3016,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Symbol":
|
|
||||||
// Symbol's argument is only used for debugging.
|
|
||||||
self.args = [];
|
|
||||||
return self;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
|
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
|
||||||
@@ -3214,7 +3098,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp instanceof AST_Function && !self.expression.is_generator) {
|
if (exp instanceof AST_Function) {
|
||||||
if (exp.body[0] instanceof AST_Return) {
|
if (exp.body[0] instanceof AST_Return) {
|
||||||
var value = exp.body[0].value;
|
var value = exp.body[0].value;
|
||||||
if (!value || value.is_constant_expression()) {
|
if (!value || value.is_constant_expression()) {
|
||||||
@@ -3883,7 +3767,7 @@ merge(Compressor.prototype, {
|
|||||||
if (fixed) {
|
if (fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
var init = fixed.evaluate(compressor);
|
var init = fixed.evaluate(compressor);
|
||||||
if (init !== fixed) {
|
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
|
||||||
init = make_node_from_constant(init, fixed);
|
init = make_node_from_constant(init, fixed);
|
||||||
var value_length = init.optimize(compressor).print_to_string().length;
|
var value_length = init.optimize(compressor).print_to_string().length;
|
||||||
var fn;
|
var fn;
|
||||||
@@ -4013,23 +3897,6 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_DefaultAssign, function(self, compressor){
|
|
||||||
if (!compressor.option("evaluate")) {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
var evaluateRight = self.right.evaluate(compressor);
|
|
||||||
|
|
||||||
// `[x = undefined] = foo` ---> `[x] = foo`
|
|
||||||
if (evaluateRight === undefined) {
|
|
||||||
self = self.left;
|
|
||||||
} else if (evaluateRight !== self.right) {
|
|
||||||
evaluateRight = make_node_from_constant(evaluateRight, self.right);
|
|
||||||
self.right = best_of_expression(evaluateRight, self.right);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_Conditional, function(self, compressor){
|
OPT(AST_Conditional, function(self, compressor){
|
||||||
if (!compressor.option("conditionals")) return self;
|
if (!compressor.option("conditionals")) return self;
|
||||||
// This looks like lift_sequences(), should probably be under "sequences"
|
// This looks like lift_sequences(), should probably be under "sequences"
|
||||||
@@ -4311,27 +4178,6 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Arrow, function(self, compressor){
|
|
||||||
if (self.body.length === 1 && self.body[0] instanceof AST_Return) {
|
|
||||||
var value = self.body[0].value;
|
|
||||||
self.body = value ? value : [];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_Class, function(self, compressor){
|
|
||||||
// HACK to avoid compress failure.
|
|
||||||
// AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_Yield, function(self, compressor){
|
|
||||||
if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) {
|
|
||||||
self.expression = null;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_VarDef, function(self, compressor){
|
OPT(AST_VarDef, function(self, compressor){
|
||||||
var defines = compressor.option("global_defs");
|
var defines = compressor.option("global_defs");
|
||||||
if (defines && HOP(defines, self.name.name)) {
|
if (defines && HOP(defines, self.name.name)) {
|
||||||
@@ -4340,32 +4186,4 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_TemplateString, function(self, compressor){
|
|
||||||
if (!compressor.option("evaluate")
|
|
||||||
|| compressor.parent() instanceof AST_PrefixedTemplateString)
|
|
||||||
return self;
|
|
||||||
|
|
||||||
var segments = [];
|
|
||||||
for (var i = 0; i < self.segments.length; i++) {
|
|
||||||
var segment = self.segments[i];
|
|
||||||
if (segment instanceof AST_Node) {
|
|
||||||
var result = segment.evaluate(compressor);
|
|
||||||
// Evaluate to constant value
|
|
||||||
// Constant value shorter than ${segment}
|
|
||||||
if (result !== segment && (result + "").length <= segment.print_to_string().length + "${}".length) {
|
|
||||||
// There should always be a previous and next segment if segment is a node
|
|
||||||
segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
segments.push(segment);
|
|
||||||
}
|
|
||||||
self.segments = segments;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_PrefixedTemplateString, function(self, compressor){
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -111,23 +111,19 @@
|
|||||||
},
|
},
|
||||||
Property: function(M) {
|
Property: function(M) {
|
||||||
var key = M.key;
|
var key = M.key;
|
||||||
var name = key.type == "Identifier" ? key.name : key.value;
|
|
||||||
var args = {
|
var args = {
|
||||||
start : my_start_token(key),
|
start : my_start_token(key),
|
||||||
end : my_end_token(M.value),
|
end : my_end_token(M.value),
|
||||||
key : name,
|
key : key.type == "Identifier" ? key.name : key.value,
|
||||||
value : from_moz(M.value)
|
value : from_moz(M.value)
|
||||||
};
|
};
|
||||||
switch (M.kind) {
|
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||||
case "init":
|
args.key = new AST_SymbolAccessor({
|
||||||
return new AST_ObjectKeyVal(args);
|
name: args.key
|
||||||
case "set":
|
});
|
||||||
args.value.name = from_moz(key);
|
args.value = new AST_Accessor(args.value);
|
||||||
return new AST_ObjectSetter(args);
|
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||||
case "get":
|
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||||
args.value.name = from_moz(key);
|
|
||||||
return new AST_ObjectGetter(args);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ArrayExpression: function(M) {
|
ArrayExpression: function(M) {
|
||||||
return new AST_Array({
|
return new AST_Array({
|
||||||
@@ -172,7 +168,7 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
VariableDeclaration: function(M) {
|
VariableDeclaration: function(M) {
|
||||||
return new (M.kind === "const" ? AST_Const : AST_Var)({
|
return new AST_Var({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M),
|
end : my_end_token(M),
|
||||||
definitions : M.declarations.map(from_moz)
|
definitions : M.declarations.map(from_moz)
|
||||||
@@ -208,7 +204,7 @@
|
|||||||
Identifier: function(M) {
|
Identifier: function(M) {
|
||||||
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
||||||
return new ( p.type == "LabeledStatement" ? AST_Label
|
return new ( p.type == "LabeledStatement" ? AST_Label
|
||||||
: p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
|
: p.type == "VariableDeclarator" && p.id === M ? AST_SymbolVar
|
||||||
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
||||||
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
||||||
: p.type == "CatchClause" ? AST_SymbolCatch
|
: p.type == "CatchClause" ? AST_SymbolCatch
|
||||||
@@ -260,10 +256,7 @@
|
|||||||
map("CallExpression", AST_Call, "callee>expression, arguments@args");
|
map("CallExpression", AST_Call, "callee>expression, arguments@args");
|
||||||
|
|
||||||
def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
|
def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
|
||||||
return {
|
return to_moz_scope("Program", M);
|
||||||
type: "Program",
|
|
||||||
body: M.body.map(to_moz)
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
|
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
|
||||||
@@ -271,7 +264,7 @@
|
|||||||
type: "FunctionDeclaration",
|
type: "FunctionDeclaration",
|
||||||
id: to_moz(M.name),
|
id: to_moz(M.name),
|
||||||
params: M.argnames.map(to_moz),
|
params: M.argnames.map(to_moz),
|
||||||
body: to_moz_block(M)
|
body: to_moz_scope("BlockStatement", M)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -280,7 +273,7 @@
|
|||||||
type: "FunctionExpression",
|
type: "FunctionExpression",
|
||||||
id: to_moz(M.name),
|
id: to_moz(M.name),
|
||||||
params: M.argnames.map(to_moz),
|
params: M.argnames.map(to_moz),
|
||||||
body: to_moz_block(M)
|
body: to_moz_scope("BlockStatement", M)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -331,7 +324,7 @@
|
|||||||
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
|
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
|
||||||
return {
|
return {
|
||||||
type: "VariableDeclaration",
|
type: "VariableDeclaration",
|
||||||
kind: M instanceof AST_Const ? "const" : "var",
|
kind: "var",
|
||||||
declarations: M.definitions.map(to_moz)
|
declarations: M.definitions.map(to_moz)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -386,11 +379,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||||
var key = (
|
var key = {
|
||||||
is_identifier(M.key)
|
type: "Literal",
|
||||||
? {type: "Identifier", name: M.key}
|
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
||||||
: {type: "Literal", value: M.key}
|
};
|
||||||
);
|
|
||||||
var kind;
|
var kind;
|
||||||
if (M instanceof AST_ObjectKeyVal) {
|
if (M instanceof AST_ObjectKeyVal) {
|
||||||
kind = "init";
|
kind = "init";
|
||||||
@@ -551,8 +543,8 @@
|
|||||||
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
||||||
exports, my_start_token, my_end_token, from_moz
|
exports, my_start_token, my_end_token, from_moz
|
||||||
);
|
);
|
||||||
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
|
me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")(
|
||||||
to_moz, to_moz_block
|
to_moz, to_moz_block, to_moz_scope
|
||||||
);
|
);
|
||||||
MOZ_TO_ME[moztype] = moz_to_me;
|
MOZ_TO_ME[moztype] = moz_to_me;
|
||||||
def_to_moz(mytype, me_to_moz);
|
def_to_moz(mytype, me_to_moz);
|
||||||
@@ -610,4 +602,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function to_moz_scope(type, node) {
|
||||||
|
var body = node.body.map(to_moz);
|
||||||
|
if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
|
||||||
|
body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
body: body
|
||||||
|
};
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
473
lib/output.js
473
lib/output.js
@@ -54,11 +54,9 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
ascii_only : false,
|
ascii_only : false,
|
||||||
ascii_identifiers: undefined,
|
|
||||||
beautify : false,
|
beautify : false,
|
||||||
bracketize : false,
|
bracketize : false,
|
||||||
comments : false,
|
comments : false,
|
||||||
ecma : 5,
|
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
indent_level : 4,
|
indent_level : 4,
|
||||||
indent_start : 0,
|
indent_start : 0,
|
||||||
@@ -71,20 +69,11 @@ function OutputStream(options) {
|
|||||||
quote_style : 0,
|
quote_style : 0,
|
||||||
semicolons : true,
|
semicolons : true,
|
||||||
shebang : true,
|
shebang : true,
|
||||||
shorthand : undefined,
|
|
||||||
source_map : null,
|
source_map : null,
|
||||||
space_colon : true,
|
|
||||||
unescape_regexps : false,
|
|
||||||
width : 80,
|
width : 80,
|
||||||
wrap_iife : false,
|
wrap_iife : false,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
if (typeof options.ascii_identifiers === 'undefined')
|
|
||||||
options.ascii_identifiers = options.ascii_only;
|
|
||||||
|
|
||||||
if (options.shorthand === undefined)
|
|
||||||
options.shorthand = options.ecma > 5;
|
|
||||||
|
|
||||||
// Convert comment option to RegExp if neccessary and set up comments filter
|
// Convert comment option to RegExp if neccessary and set up comments filter
|
||||||
var comment_filter = return_false; // Default case, throw all comments away
|
var comment_filter = return_false; // Default case, throw all comments away
|
||||||
if (options.comments) {
|
if (options.comments) {
|
||||||
@@ -120,19 +109,9 @@ function OutputStream(options) {
|
|||||||
var OUTPUT = "";
|
var OUTPUT = "";
|
||||||
|
|
||||||
function to_ascii(str, identifier) {
|
function to_ascii(str, identifier) {
|
||||||
return str.replace(/[\ud800-\udbff][\udc00-\udfff]|[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
||||||
var code = get_full_char_code(ch, 0).toString(16);
|
var code = ch.charCodeAt(0).toString(16);
|
||||||
|
if (code.length <= 2 && !identifier) {
|
||||||
if ((identifier && code.length === 1 && options.ecma >= 6) || code.length > 4) {
|
|
||||||
if (options.ecma < 6) {
|
|
||||||
if (identifier) {
|
|
||||||
return ch; // no \u{} support
|
|
||||||
}
|
|
||||||
return "\\u" + ch.charCodeAt(0).toString(16) + "\\u"
|
|
||||||
+ ch.charCodeAt(1).toString(16);
|
|
||||||
}
|
|
||||||
return "\\u{" + code + "}";
|
|
||||||
} else if (code.length <= 2 && !identifier) {
|
|
||||||
while (code.length < 2) code = "0" + code;
|
while (code.length < 2) code = "0" + code;
|
||||||
return "\\x" + code;
|
return "\\x" + code;
|
||||||
} else {
|
} else {
|
||||||
@@ -160,7 +139,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(get_full_char(str, i+1)) ? "\\x00" : "\\0";
|
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
@@ -170,11 +149,7 @@ function OutputStream(options) {
|
|||||||
function quote_double() {
|
function quote_double() {
|
||||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||||
}
|
}
|
||||||
function quote_template() {
|
|
||||||
return '`' + str.replace(/`/g, '\\`') + '`';
|
|
||||||
}
|
|
||||||
if (options.ascii_only) str = to_ascii(str);
|
if (options.ascii_only) str = to_ascii(str);
|
||||||
if (quote === "`") return quote_template();
|
|
||||||
switch (options.quote_style) {
|
switch (options.quote_style) {
|
||||||
case 1:
|
case 1:
|
||||||
return quote_single();
|
return quote_single();
|
||||||
@@ -199,7 +174,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function make_name(name) {
|
function make_name(name) {
|
||||||
name = name.toString();
|
name = name.toString();
|
||||||
if (options.ascii_identifiers)
|
if (options.ascii_only)
|
||||||
name = to_ascii(name, true);
|
name = to_ascii(name, true);
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
@@ -236,8 +211,8 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function print(str) {
|
function print(str) {
|
||||||
str = String(str);
|
str = String(str);
|
||||||
var ch = get_full_char(str, 0);
|
var ch = str.charAt(0);
|
||||||
var prev = get_full_char(last, last.length - 1);
|
var prev = last.charAt(last.length - 1);
|
||||||
if (might_need_semicolon) {
|
if (might_need_semicolon) {
|
||||||
might_need_semicolon = false;
|
might_need_semicolon = false;
|
||||||
|
|
||||||
@@ -301,10 +276,6 @@ function OutputStream(options) {
|
|||||||
last = str;
|
last = str;
|
||||||
};
|
};
|
||||||
|
|
||||||
var star = function(){
|
|
||||||
print("*");
|
|
||||||
}
|
|
||||||
|
|
||||||
var space = options.beautify ? function() {
|
var space = options.beautify ? function() {
|
||||||
print(" ");
|
print(" ");
|
||||||
} : function() {
|
} : function() {
|
||||||
@@ -384,7 +355,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function colon() {
|
function colon() {
|
||||||
print(":");
|
print(":");
|
||||||
if (options.space_colon) space();
|
space();
|
||||||
};
|
};
|
||||||
|
|
||||||
var add_mapping = options.source_map ? function(token, name) {
|
var add_mapping = options.source_map ? function(token, name) {
|
||||||
@@ -424,7 +395,6 @@ function OutputStream(options) {
|
|||||||
should_break : function() { return options.width && this.current_width() >= options.width },
|
should_break : function() { return options.width && this.current_width() >= options.width },
|
||||||
newline : newline,
|
newline : newline,
|
||||||
print : print,
|
print : print,
|
||||||
star : star,
|
|
||||||
space : space,
|
space : space,
|
||||||
comma : comma,
|
comma : comma,
|
||||||
colon : colon,
|
colon : colon,
|
||||||
@@ -444,10 +414,6 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
print(encoded);
|
print(encoded);
|
||||||
},
|
},
|
||||||
print_template_string_chars: function(str) {
|
|
||||||
var encoded = encode_string(str, '`').replace(/\${/g, "\\${");
|
|
||||||
return print(encoded.substr(1, encoded.length - 2));
|
|
||||||
},
|
|
||||||
encode_string : encode_string,
|
encode_string : encode_string,
|
||||||
next_indent : next_indent,
|
next_indent : next_indent,
|
||||||
with_indent : with_indent,
|
with_indent : with_indent,
|
||||||
@@ -608,11 +574,6 @@ function OutputStream(options) {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Arrow, function(output){
|
|
||||||
var p = output.parent();
|
|
||||||
return p instanceof AST_PropAccess && p.expression === this;
|
|
||||||
});
|
|
||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output){
|
PARENS(AST_Object, function(output){
|
||||||
@@ -622,29 +583,20 @@ function OutputStream(options) {
|
|||||||
PARENS(AST_Unary, function(output){
|
PARENS(AST_Unary, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_PropAccess && p.expression === this
|
return p instanceof AST_PropAccess && p.expression === this
|
||||||
|| p instanceof AST_Call && p.expression === this
|
|| p instanceof AST_Call && p.expression === this;
|
||||||
|| p instanceof AST_Binary
|
|
||||||
&& p.operator === "**"
|
|
||||||
&& this instanceof AST_UnaryPrefix
|
|
||||||
&& p.left === this
|
|
||||||
&& this.operator !== "++"
|
|
||||||
&& this.operator !== "--";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Sequence, function(output){
|
PARENS(AST_Sequence, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
||||||
|| p instanceof AST_Unary // !(foo, bar, baz)
|
|| p instanceof AST_Unary // !(foo, bar, baz)
|
||||||
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
||||||
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
||||||
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
||||||
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
* ==> 20 (side effect, set a := 10 and b := 20) */
|
* ==> 20 (side effect, set a := 10 and b := 20) */
|
||||||
|| p instanceof AST_Arrow // x => (x, x)
|
|
||||||
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
|
|
||||||
|| (p instanceof AST_Class && p.extends === this) // class D extends (calls++, C) {}
|
|
||||||
;
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -671,24 +623,6 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Yield, function(output){
|
|
||||||
var p = output.parent();
|
|
||||||
// (yield 1) + (yield 2)
|
|
||||||
// a = yield 3
|
|
||||||
if (p instanceof AST_Binary && p.operator !== "=")
|
|
||||||
return true;
|
|
||||||
// (yield 1) ? yield 2 : yield 3
|
|
||||||
if (p instanceof AST_Conditional && p.condition === this)
|
|
||||||
return true;
|
|
||||||
// -(yield 4)
|
|
||||||
if (p instanceof AST_Unary)
|
|
||||||
return true;
|
|
||||||
// (yield x).foo
|
|
||||||
// (yield x)['foo']
|
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
PARENS(AST_PropAccess, function(output){
|
PARENS(AST_PropAccess, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_New && p.expression === this) {
|
if (p instanceof AST_New && p.expression === this) {
|
||||||
@@ -758,9 +692,6 @@ function OutputStream(options) {
|
|||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
return true;
|
return true;
|
||||||
// ({a, b} = {a: 1, b: 2}), a destructuring assignment
|
|
||||||
if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false)
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
@@ -769,28 +700,6 @@ function OutputStream(options) {
|
|||||||
output.print_string(self.value, self.quote);
|
output.print_string(self.value, self.quote);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_Expansion, function (self, output) {
|
|
||||||
output.print('...');
|
|
||||||
self.expression.print(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_Destructuring, function (self, output) {
|
|
||||||
output.print(self.is_array ? "[" : "{");
|
|
||||||
var first = true;
|
|
||||||
var len = self.names.length;
|
|
||||||
self.names.forEach(function (name, i) {
|
|
||||||
if (first) first = false; else { output.comma(); output.space(); }
|
|
||||||
name.print(output);
|
|
||||||
// If the final element is a hole, we need to make sure it
|
|
||||||
// doesn't look like a trailing comma, by inserting an actual
|
|
||||||
// trailing comma.
|
|
||||||
if (i === len - 1 && name instanceof AST_Hole)
|
|
||||||
output.comma();
|
|
||||||
})
|
|
||||||
output.print(self.is_array ? "]" : "}");
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_Debugger, function(self, output){
|
DEFPRINT(AST_Debugger, function(self, output){
|
||||||
output.print("debugger");
|
output.print("debugger");
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
@@ -915,11 +824,7 @@ function OutputStream(options) {
|
|||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.init.print(output);
|
self.init.print(output);
|
||||||
output.space();
|
output.space();
|
||||||
if (self instanceof AST_ForOf) {
|
output.print("in");
|
||||||
output.print("of");
|
|
||||||
} else {
|
|
||||||
output.print("in");
|
|
||||||
}
|
|
||||||
output.space();
|
output.space();
|
||||||
self.object.print(output);
|
self.object.print(output);
|
||||||
});
|
});
|
||||||
@@ -941,19 +846,10 @@ function OutputStream(options) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
if (!nokeyword) {
|
if (!nokeyword) {
|
||||||
output.print("function");
|
output.print("function");
|
||||||
if (this.is_generator) {
|
|
||||||
output.star();
|
|
||||||
}
|
|
||||||
if (self.name) {
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (self.name instanceof AST_Symbol) {
|
if (self.name) {
|
||||||
|
output.space();
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
} else if (nokeyword && self.name instanceof AST_Node) {
|
|
||||||
output.with_square(function() {
|
|
||||||
self.name.print(output); // Computed method name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.argnames.forEach(function(arg, i){
|
self.argnames.forEach(function(arg, i){
|
||||||
@@ -968,56 +864,6 @@ function OutputStream(options) {
|
|||||||
self._do_print(output);
|
self._do_print(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
|
|
||||||
self.prefix.print(output);
|
|
||||||
self.template_string.print(output);
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_TemplateString, function(self, output) {
|
|
||||||
var is_tagged = output.parent() instanceof AST_PrefixedTemplateString;
|
|
||||||
|
|
||||||
output.print("`");
|
|
||||||
for (var i = 0; i < self.segments.length; i++) {
|
|
||||||
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
|
|
||||||
output.print("${");
|
|
||||||
self.segments[i].print(output);
|
|
||||||
output.print("}");
|
|
||||||
} else if (is_tagged) {
|
|
||||||
output.print(self.segments[i].raw);
|
|
||||||
} else {
|
|
||||||
output.print_template_string_chars(self.segments[i].value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output.print("`");
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Arrow.DEFMETHOD("_do_print", function(output){
|
|
||||||
var self = this;
|
|
||||||
var parent = output.parent();
|
|
||||||
var needs_parens = parent instanceof AST_Binary ||
|
|
||||||
parent instanceof AST_Unary ||
|
|
||||||
(parent instanceof AST_Call && self === parent.expression);
|
|
||||||
if (needs_parens) { output.print("(") }
|
|
||||||
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
|
|
||||||
self.argnames[0].print(output);
|
|
||||||
} else {
|
|
||||||
output.with_parens(function(){
|
|
||||||
self.argnames.forEach(function(arg, i){
|
|
||||||
if (i) output.comma();
|
|
||||||
arg.print(output);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
output.space();
|
|
||||||
output.print('=>');
|
|
||||||
output.space();
|
|
||||||
if (self.body instanceof AST_Node) {
|
|
||||||
this.body.print(output);
|
|
||||||
} else {
|
|
||||||
print_bracketed(this.body, output);
|
|
||||||
}
|
|
||||||
if (needs_parens) { output.print(")") }
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ exits ]----- */
|
/* -----[ exits ]----- */
|
||||||
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
|
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
|
||||||
output.print(kind);
|
output.print(kind);
|
||||||
@@ -1034,17 +880,6 @@ function OutputStream(options) {
|
|||||||
self._do_print(output, "throw");
|
self._do_print(output, "throw");
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ yield ]----- */
|
|
||||||
|
|
||||||
DEFPRINT(AST_Yield, function(self, output){
|
|
||||||
var star = self.is_star ? "*" : "";
|
|
||||||
output.print("yield" + star);
|
|
||||||
if (self.expression) {
|
|
||||||
output.space();
|
|
||||||
self.expression.print(output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ loop control ]----- */
|
/* -----[ loop control ]----- */
|
||||||
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
|
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
|
||||||
output.print(kind);
|
output.print(kind);
|
||||||
@@ -1193,107 +1028,9 @@ function OutputStream(options) {
|
|||||||
if (!avoid_semicolon)
|
if (!avoid_semicolon)
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Let, function(self, output){
|
|
||||||
self._do_print(output, "let");
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_Var, function(self, output){
|
DEFPRINT(AST_Var, function(self, output){
|
||||||
self._do_print(output, "var");
|
self._do_print(output, "var");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Const, function(self, output){
|
|
||||||
self._do_print(output, "const");
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_Import, function(self, output) {
|
|
||||||
output.print("import");
|
|
||||||
output.space();
|
|
||||||
if (self.imported_name) {
|
|
||||||
self.imported_name.print(output);
|
|
||||||
}
|
|
||||||
if (self.imported_name && self.imported_names) {
|
|
||||||
output.print(",");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
if (self.imported_names) {
|
|
||||||
if (self.imported_names.length === 1 && self.imported_names[0].foreign_name.name === "*") {
|
|
||||||
self.imported_names[0].print(output);
|
|
||||||
} else {
|
|
||||||
output.print("{");
|
|
||||||
self.imported_names.forEach(function (name_import, i) {
|
|
||||||
output.space();
|
|
||||||
name_import.print(output);
|
|
||||||
if (i < self.imported_names.length - 1) {
|
|
||||||
output.print(",");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
output.space();
|
|
||||||
output.print("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (self.imported_name || self.imported_names) {
|
|
||||||
output.space();
|
|
||||||
output.print("from")
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
self.module_name.print(output);
|
|
||||||
output.semicolon();
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_NameImport, function(self, output) {
|
|
||||||
var definition = self.name.definition();
|
|
||||||
var names_are_different =
|
|
||||||
(definition && definition.mangled_name || self.name.name) !==
|
|
||||||
self.foreign_name.name;
|
|
||||||
if (names_are_different) {
|
|
||||||
output.print(self.foreign_name.name);
|
|
||||||
output.space();
|
|
||||||
output.print("as");
|
|
||||||
output.space();
|
|
||||||
self.name.print(output);
|
|
||||||
} else {
|
|
||||||
self.name.print(output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_Export, function(self, output) {
|
|
||||||
output.print("export");
|
|
||||||
output.space();
|
|
||||||
if (self.is_default) {
|
|
||||||
output.print("default");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
if (self.exported_names) {
|
|
||||||
output.space();
|
|
||||||
|
|
||||||
if (self.exported_names.length === 1 && self.exported_names[0].name.name === "*") {
|
|
||||||
self.exported_names[0].print(output);
|
|
||||||
} else {
|
|
||||||
output.print("{");
|
|
||||||
self.exported_names.forEach(function (name_import, i) {
|
|
||||||
output.space();
|
|
||||||
name_import.print(output);
|
|
||||||
if (i < self.exported_names.length - 1) {
|
|
||||||
output.print(",");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
output.space();
|
|
||||||
output.print("}");
|
|
||||||
}
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
else if (self.exported_value) {
|
|
||||||
self.exported_value.print(output);
|
|
||||||
} else if (self.exported_definition) {
|
|
||||||
self.exported_definition.print(output);
|
|
||||||
}
|
|
||||||
if (self.module_name) {
|
|
||||||
output.space();
|
|
||||||
output.print("from");
|
|
||||||
output.space();
|
|
||||||
self.module_name.print(output);
|
|
||||||
}
|
|
||||||
output.semicolon();
|
|
||||||
});
|
|
||||||
|
|
||||||
function parenthesize_for_noin(node, output, noin) {
|
function parenthesize_for_noin(node, output, noin) {
|
||||||
if (!noin) node.print(output);
|
if (!noin) node.print(output);
|
||||||
@@ -1466,35 +1203,9 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
else output.print("{}");
|
else output.print("{}");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Class, function(self, output){
|
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
||||||
output.print("class");
|
var key = self.key;
|
||||||
output.space();
|
var quote = self.quote;
|
||||||
if (self.name) {
|
|
||||||
self.name.print(output);
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
if (self.extends) {
|
|
||||||
output.print("extends");
|
|
||||||
output.space();
|
|
||||||
self.extends.print(output);
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
if (self.properties.length > 0) output.with_block(function(){
|
|
||||||
self.properties.forEach(function(prop, i){
|
|
||||||
if (i) {
|
|
||||||
output.newline();
|
|
||||||
}
|
|
||||||
output.indent();
|
|
||||||
prop.print(output);
|
|
||||||
});
|
|
||||||
output.newline();
|
|
||||||
});
|
|
||||||
else output.print("{}");
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_NewTarget, function(self, output) {
|
|
||||||
output.print("new.target");
|
|
||||||
});
|
|
||||||
AST_ObjectProperty.DEFMETHOD("print_property_name", function(key, quote, output) {
|
|
||||||
if (output.option("quote_keys")) {
|
if (output.option("quote_keys")) {
|
||||||
output.print_string(key + "");
|
output.print_string(key + "");
|
||||||
} else if ((typeof key == "number"
|
} else if ((typeof key == "number"
|
||||||
@@ -1511,98 +1222,29 @@ function OutputStream(options) {
|
|||||||
} else {
|
} else {
|
||||||
output.print_string(key, quote);
|
output.print_string(key, quote);
|
||||||
}
|
}
|
||||||
});
|
output.colon();
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
self.value.print(output);
|
||||||
function get_name(self) {
|
|
||||||
var def = self.definition();
|
|
||||||
return def ? def.mangled_name || def.name : self.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
var allowShortHand = output.option("shorthand");
|
|
||||||
if (allowShortHand &&
|
|
||||||
self.value instanceof AST_Symbol &&
|
|
||||||
is_identifier_string(self.key) &&
|
|
||||||
get_name(self.value) === self.key
|
|
||||||
) {
|
|
||||||
self.print_property_name(self.key, self.quote, output);
|
|
||||||
|
|
||||||
} else if (allowShortHand &&
|
|
||||||
self.value instanceof AST_DefaultAssign &&
|
|
||||||
self.value.left instanceof AST_Symbol &&
|
|
||||||
is_identifier_string(self.key) &&
|
|
||||||
get_name(self.value.left) === self.key
|
|
||||||
) {
|
|
||||||
self.print_property_name(self.key, self.quote, output);
|
|
||||||
output.print("=");
|
|
||||||
self.value.right.print(output);
|
|
||||||
} else {
|
|
||||||
if (!(self.key instanceof AST_Node)) {
|
|
||||||
self.print_property_name(self.key, self.quote, output);
|
|
||||||
} else {
|
|
||||||
output.with_square(function() {
|
|
||||||
self.key.print(output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
output.colon();
|
|
||||||
self.value.print(output);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, self, output) {
|
|
||||||
if (self.static) {
|
|
||||||
output.print("static");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
output.print(type);
|
|
||||||
output.space();
|
|
||||||
if (self.key instanceof AST_SymbolMethod) {
|
|
||||||
self.print_property_name(self.key.name, self.quote, output);
|
|
||||||
} else {
|
|
||||||
output.with_square(function() {
|
|
||||||
self.key.print(output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.value._do_print(output, true);
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectSetter, function(self, output){
|
DEFPRINT(AST_ObjectSetter, function(self, output){
|
||||||
self._print_getter_setter("set", self, output);
|
output.print("set");
|
||||||
});
|
output.space();
|
||||||
DEFPRINT(AST_ObjectGetter, function(self, output){
|
self.key.print(output);
|
||||||
self._print_getter_setter("get", self, output);
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_ConciseMethod, function(self, output){
|
|
||||||
if (self.static) {
|
|
||||||
output.print("static");
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
if (self.is_generator) {
|
|
||||||
output.print("*");
|
|
||||||
}
|
|
||||||
if (self.key instanceof AST_SymbolMethod) {
|
|
||||||
self.print_property_name(self.key.name, self.quote, output);
|
|
||||||
} else {
|
|
||||||
output.with_square(function() {
|
|
||||||
self.key.print(output);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.value._do_print(output, true);
|
self.value._do_print(output, true);
|
||||||
});
|
});
|
||||||
AST_Symbol.DEFMETHOD("_do_print", function(output){
|
DEFPRINT(AST_ObjectGetter, function(self, output){
|
||||||
var def = this.definition();
|
output.print("get");
|
||||||
output.print_name(def ? def.mangled_name || def.name : this.name);
|
output.space();
|
||||||
|
self.key.print(output);
|
||||||
|
self.value._do_print(output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Symbol, function (self, output) {
|
DEFPRINT(AST_Symbol, function(self, output){
|
||||||
self._do_print(output);
|
var def = self.definition();
|
||||||
});
|
output.print_name(def ? def.mangled_name || def.name : self.name);
|
||||||
DEFPRINT(AST_SymbolDeclaration, function(self, output){
|
|
||||||
self._do_print(output);
|
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Hole, noop);
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_This, function(self, output){
|
DEFPRINT(AST_This, function(self, output){
|
||||||
output.print("this");
|
output.print("this");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Super, function(self, output){
|
|
||||||
output.print("super");
|
|
||||||
});
|
|
||||||
DEFPRINT(AST_Constant, function(self, output){
|
DEFPRINT(AST_Constant, function(self, output){
|
||||||
output.print(self.getValue());
|
output.print(self.getValue());
|
||||||
});
|
});
|
||||||
@@ -1617,45 +1259,14 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function regexp_safe_literal(code) {
|
|
||||||
return [
|
|
||||||
0x5c , // \
|
|
||||||
0x2f , // /
|
|
||||||
0x2e , // .
|
|
||||||
0x2b , // +
|
|
||||||
0x2a , // *
|
|
||||||
0x3f , // ?
|
|
||||||
0x28 , // (
|
|
||||||
0x29 , // )
|
|
||||||
0x5b , // [
|
|
||||||
0x5d , // ]
|
|
||||||
0x7b , // {
|
|
||||||
0x7d , // }
|
|
||||||
0x24 , // $
|
|
||||||
0x5e , // ^
|
|
||||||
0x3a , // :
|
|
||||||
0x7c , // |
|
|
||||||
0x21 , // !
|
|
||||||
0x0a , // \n
|
|
||||||
0x0d , // \r
|
|
||||||
0x00 , // \0
|
|
||||||
0xfeff , // Unicode BOM
|
|
||||||
0x2028 , // unicode "line separator"
|
|
||||||
0x2029 , // unicode "paragraph separator"
|
|
||||||
].indexOf(code) < 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFPRINT(AST_RegExp, function(self, output){
|
DEFPRINT(AST_RegExp, function(self, output){
|
||||||
var str = self.getValue().toString();
|
var regexp = self.getValue();
|
||||||
|
var str = regexp.toString();
|
||||||
|
if (regexp.raw_source) {
|
||||||
|
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||||
|
}
|
||||||
if (output.option("ascii_only")) {
|
if (output.option("ascii_only")) {
|
||||||
str = output.to_ascii(str);
|
str = output.to_ascii(str);
|
||||||
} else if (output.option("unescape_regexps")) {
|
|
||||||
str = str.split("\\\\").map(function(str){
|
|
||||||
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
|
|
||||||
var code = parseInt(s.substr(2), 16);
|
|
||||||
return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
|
|
||||||
});
|
|
||||||
}).join("\\\\");
|
|
||||||
}
|
}
|
||||||
output.print(str);
|
output.print(str);
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
|||||||
1533
lib/parse.js
1533
lib/parse.js
File diff suppressed because one or more lines are too long
@@ -44,15 +44,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function find_builtins(reserved) {
|
function find_builtins(reserved) {
|
||||||
|
|
||||||
// Compatibility fix for some standard defined globals not defined on every js environment
|
|
||||||
var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"];
|
|
||||||
var objects = {};
|
|
||||||
|
|
||||||
new_globals.forEach(function (new_global) {
|
|
||||||
objects[new_global] = global[new_global] || new Function();
|
|
||||||
});
|
|
||||||
|
|
||||||
// NaN will be included due to Number.NaN
|
// NaN will be included due to Number.NaN
|
||||||
[
|
[
|
||||||
"null",
|
"null",
|
||||||
@@ -64,15 +55,7 @@ function find_builtins(reserved) {
|
|||||||
].forEach(add);
|
].forEach(add);
|
||||||
[ Object, Array, Function, Number,
|
[ Object, Array, Function, Number,
|
||||||
String, Boolean, Error, Math,
|
String, Boolean, Error, Math,
|
||||||
Date, RegExp, objects.Symbol, ArrayBuffer,
|
Date, RegExp
|
||||||
DataView, decodeURI, decodeURIComponent,
|
|
||||||
encodeURI, encodeURIComponent, eval, EvalError,
|
|
||||||
Float32Array, Float64Array, Int8Array, Int16Array,
|
|
||||||
Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat,
|
|
||||||
parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError,
|
|
||||||
objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array,
|
|
||||||
Uint8ClampedArray, Uint16Array, Uint32Array, URIError,
|
|
||||||
objects.WeakMap, objects.WeakSet
|
|
||||||
].forEach(function(ctor){
|
].forEach(function(ctor){
|
||||||
Object.getOwnPropertyNames(ctor).map(add);
|
Object.getOwnPropertyNames(ctor).map(add);
|
||||||
if (ctor.prototype) {
|
if (ctor.prototype) {
|
||||||
@@ -137,9 +120,6 @@ function mangle_properties(ast, options) {
|
|||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, keep_quoted);
|
addStrings(node.property, keep_quoted);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ConciseMethod) {
|
|
||||||
add(node.name.name);
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// step 2: transform the tree, renaming properties
|
// step 2: transform the tree, renaming properties
|
||||||
@@ -159,11 +139,6 @@ function mangle_properties(ast, options) {
|
|||||||
if (!keep_quoted)
|
if (!keep_quoted)
|
||||||
node.property = mangleStrings(node.property);
|
node.property = mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ConciseMethod) {
|
|
||||||
if (should_mangle(node.name.name)) {
|
|
||||||
node.name.name = mangle(node.name.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// else if (node instanceof AST_String) {
|
// else if (node instanceof AST_String) {
|
||||||
// if (should_mangle(node.value)) {
|
// if (should_mangle(node.value)) {
|
||||||
// AST_Node.warn(
|
// AST_Node.warn(
|
||||||
|
|||||||
149
lib/scope.js
149
lib/scope.js
@@ -49,9 +49,7 @@ function SymbolDef(scope, index, orig) {
|
|||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.references = [];
|
this.references = [];
|
||||||
this.global = false;
|
this.global = false;
|
||||||
this.export = false;
|
|
||||||
this.mangled_name = null;
|
this.mangled_name = null;
|
||||||
this.object_destructuring_arg = false;
|
|
||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.id = SymbolDef.next_id++;
|
this.id = SymbolDef.next_id++;
|
||||||
@@ -64,17 +62,11 @@ SymbolDef.prototype = {
|
|||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
|
|
||||||
return (this.global && !options.toplevel)
|
return (this.global && !options.toplevel)
|
||||||
|| this.export
|
|
||||||
|| this.object_destructuring_arg
|
|
||||||
|| this.undeclared
|
|| this.undeclared
|
||||||
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
||||||
|| (options.keep_fnames
|
|| (options.keep_fnames
|
||||||
&& (this.orig[0] instanceof AST_SymbolLambda
|
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||||
|| this.orig[0] instanceof AST_SymbolDefun))
|
|| this.orig[0] instanceof AST_SymbolDefun));
|
||||||
|| this.orig[0] instanceof AST_SymbolMethod
|
|
||||||
|| (options.keep_classnames
|
|
||||||
&& (this.orig[0] instanceof AST_SymbolClass
|
|
||||||
|| this.orig[0] instanceof AST_SymbolDefClass));
|
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
@@ -109,29 +101,15 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var labels = new Dictionary();
|
var labels = new Dictionary();
|
||||||
var defun = null;
|
var defun = null;
|
||||||
var in_destructuring = null;
|
|
||||||
var in_export = false;
|
|
||||||
var in_block = 0;
|
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node.is_block_scope()) {
|
if (node instanceof AST_Catch) {
|
||||||
var save_scope = scope;
|
var save_scope = scope;
|
||||||
scope = new AST_Scope(node);
|
scope = new AST_Scope(node);
|
||||||
scope.init_scope_vars(save_scope);
|
scope.init_scope_vars(save_scope);
|
||||||
if (!(node instanceof AST_Scope)) {
|
|
||||||
scope.uses_with = save_scope.uses_with;
|
|
||||||
scope.uses_eval = save_scope.uses_eval;
|
|
||||||
scope.directives = save_scope.directives;
|
|
||||||
}
|
|
||||||
descend();
|
descend();
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Destructuring && node.is_array === false) {
|
|
||||||
in_destructuring = node; // These don't nest
|
|
||||||
descend();
|
|
||||||
in_destructuring = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
node.init_scope_vars(scope);
|
node.init_scope_vars(scope);
|
||||||
var save_scope = scope;
|
var save_scope = scope;
|
||||||
@@ -145,22 +123,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
labels = save_labels;
|
labels = save_labels;
|
||||||
return true; // don't descend again in TreeWalker
|
return true; // don't descend again in TreeWalker
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Export) {
|
|
||||||
in_export = true;
|
|
||||||
descend();
|
|
||||||
in_export = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_BlockStatement
|
|
||||||
|| node instanceof AST_Switch
|
|
||||||
|| node instanceof AST_Try
|
|
||||||
|| node instanceof AST_Catch
|
|
||||||
|| node instanceof AST_Finally) {
|
|
||||||
in_block++;
|
|
||||||
descend();
|
|
||||||
in_block--;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
var l = node.label;
|
var l = node.label;
|
||||||
if (labels.has(l.name)) {
|
if (labels.has(l.name)) {
|
||||||
@@ -179,15 +141,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolFunarg) {
|
|
||||||
node.object_destructuring_arg = !!in_destructuring;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
node.thedef = node;
|
node.thedef = node;
|
||||||
node.references = [];
|
node.references = [];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
defun.def_function(node, in_export, in_block);
|
defun.def_function(node);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// Careful here, the scope where this should be defined is
|
||||||
@@ -195,28 +154,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
// scope when we encounter the AST_Defun node (which is
|
// scope when we encounter the AST_Defun node (which is
|
||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
// instanceof AST_Scope) but we get to the symbol a bit
|
||||||
// later.
|
// later.
|
||||||
var parent_lambda = defun.parent_scope;
|
(node.scope = defun.parent_scope).def_function(node);
|
||||||
while (parent_lambda.is_block_scope()) {
|
|
||||||
parent_lambda = parent_lambda.parent_scope;
|
|
||||||
}
|
|
||||||
(node.scope = parent_lambda).def_function(node, in_export, in_block);
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolClass) {
|
else if (node instanceof AST_SymbolVar) {
|
||||||
defun.def_variable(node, in_export, in_block);
|
defun.def_variable(node);
|
||||||
}
|
|
||||||
else if (node instanceof AST_SymbolImport) {
|
|
||||||
scope.def_variable(node, in_export, in_block);
|
|
||||||
}
|
|
||||||
else if (node instanceof AST_SymbolDefClass) {
|
|
||||||
// This deals with the name of the class being available
|
|
||||||
// inside the class.
|
|
||||||
(node.scope = defun.parent_scope).def_function(node, in_export, in_block);
|
|
||||||
}
|
|
||||||
else if (node instanceof AST_SymbolVar
|
|
||||||
|| node instanceof AST_SymbolLet
|
|
||||||
|| node instanceof AST_SymbolConst) {
|
|
||||||
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export, in_block);
|
|
||||||
def.destructuring = in_destructuring;
|
|
||||||
if (defun !== scope) {
|
if (defun !== scope) {
|
||||||
node.mark_enclosed(options);
|
node.mark_enclosed(options);
|
||||||
var def = scope.find_variable(node);
|
var def = scope.find_variable(node);
|
||||||
@@ -227,7 +168,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
scope.def_variable(node, in_export, in_block).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_LabelRef) {
|
else if (node instanceof AST_LabelRef) {
|
||||||
var sym = labels.get(node.name);
|
var sym = labels.get(node.name);
|
||||||
@@ -243,7 +184,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
var func = null;
|
var func = null;
|
||||||
var cls = null;
|
|
||||||
var globals = self.globals = new Dictionary();
|
var globals = self.globals = new Dictionary();
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node instanceof AST_Lambda) {
|
if (node instanceof AST_Lambda) {
|
||||||
@@ -253,13 +193,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
func = prev_func;
|
func = prev_func;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Class) {
|
|
||||||
var prev_cls = cls;
|
|
||||||
cls = node;
|
|
||||||
descend();
|
|
||||||
cls = prev_cls;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_LoopControl && node.label) {
|
if (node instanceof AST_LoopControl && node.label) {
|
||||||
node.label.thedef.references.push(node);
|
node.label.thedef.references.push(node);
|
||||||
return true;
|
return true;
|
||||||
@@ -331,27 +264,10 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
|
|||||||
this.cname = -1; // the current index for mangling functions/variables
|
this.cname = -1; // the current index for mangling functions/variables
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("is_block_scope", function(){
|
|
||||||
return false; // Behaviour will be overridden by AST_Block
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Block.DEFMETHOD("is_block_scope", function(){
|
|
||||||
return (
|
|
||||||
!(this instanceof AST_Lambda) &&
|
|
||||||
!(this instanceof AST_Toplevel) &&
|
|
||||||
!(this instanceof AST_Class) &&
|
|
||||||
!(this instanceof AST_SwitchBranch)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_IterationStatement.DEFMETHOD("is_block_scope", function(){
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
this.def_variable(new AST_SymbolConst({
|
this.def_variable(new AST_SymbolFunarg({
|
||||||
name: "arguments",
|
name: "arguments",
|
||||||
start: this.start,
|
start: this.start,
|
||||||
end: this.end
|
end: this.end
|
||||||
@@ -384,24 +300,16 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|
|||||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_function", function(symbol, in_export, in_block){
|
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
||||||
this.functions.set(symbol.name, this.def_variable(symbol, in_export, in_block));
|
this.functions.set(symbol.name, this.def_variable(symbol));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export, in_block){
|
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
||||||
var def;
|
var def;
|
||||||
if (!this.variables.has(symbol.name)) {
|
if (!this.variables.has(symbol.name)) {
|
||||||
def = new SymbolDef(this, this.variables.size(), symbol);
|
def = new SymbolDef(this, this.variables.size(), symbol);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.object_destructuring_arg = symbol.object_destructuring_arg;
|
def.global = !this.parent_scope;
|
||||||
if (in_export) {
|
|
||||||
def.export = true;
|
|
||||||
}
|
|
||||||
if (in_block && symbol instanceof AST_SymbolBlockDeclaration) {
|
|
||||||
def.global = false;
|
|
||||||
} else {
|
|
||||||
def.global = !this.parent_scope;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
def = this.variables.get(symbol.name);
|
def = this.variables.get(symbol.name);
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
@@ -449,13 +357,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||||
var def = this.definition();
|
return this.definition().unmangleable(options);
|
||||||
return def && def.unmangleable(options);
|
|
||||||
});
|
|
||||||
|
|
||||||
// property accessors are not mangleable
|
|
||||||
AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// labels are always mangleable
|
// labels are always mangleable
|
||||||
@@ -492,7 +394,6 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
|||||||
return defaults(options, {
|
return defaults(options, {
|
||||||
eval : false,
|
eval : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
keep_classnames: false,
|
|
||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
reserved : [],
|
reserved : [],
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
@@ -544,19 +445,13 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var mangle_with_block_scope =
|
if (!options.ie8 && node instanceof AST_SymbolCatch) {
|
||||||
(!options.ie8 && node instanceof AST_SymbolCatch) ||
|
|
||||||
node instanceof AST_SymbolBlockDeclaration;
|
|
||||||
if (mangle_with_block_scope) {
|
|
||||||
to_mangle.push(node.definition());
|
to_mangle.push(node.definition());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
to_mangle.forEach(function(def){
|
to_mangle.forEach(function(def){ def.mangle(options) });
|
||||||
if (def.destructuring && !def.destructuring.is_array) return;
|
|
||||||
def.mangle(options);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.cache) {
|
if (options.cache) {
|
||||||
options.cache.cname = this.cname;
|
options.cache.cname = this.cname;
|
||||||
@@ -590,8 +485,6 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
|||||||
}
|
}
|
||||||
else if (node instanceof AST_Var)
|
else if (node instanceof AST_Var)
|
||||||
base54.consider("var");
|
base54.consider("var");
|
||||||
else if (node instanceof AST_Const)
|
|
||||||
base54.consider("const");
|
|
||||||
else if (node instanceof AST_Lambda)
|
else if (node instanceof AST_Lambda)
|
||||||
base54.consider("function");
|
base54.consider("function");
|
||||||
else if (node instanceof AST_For)
|
else if (node instanceof AST_For)
|
||||||
@@ -607,27 +500,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
|||||||
else if (node instanceof AST_With)
|
else if (node instanceof AST_With)
|
||||||
base54.consider("with");
|
base54.consider("with");
|
||||||
else if (node instanceof AST_ObjectSetter)
|
else if (node instanceof AST_ObjectSetter)
|
||||||
base54.consider("set" + (typeof node.key === "string" ? node.key : ""));
|
base54.consider("set" + node.key);
|
||||||
else if (node instanceof AST_ObjectGetter)
|
else if (node instanceof AST_ObjectGetter)
|
||||||
base54.consider("get" + (typeof node.key === "string" ? node.key : ""));
|
base54.consider("get" + node.key);
|
||||||
else if (node instanceof AST_ObjectKeyVal && typeof node.key === "string")
|
else if (node instanceof AST_ObjectKeyVal)
|
||||||
base54.consider(node.key);
|
|
||||||
else if (node instanceof AST_ConciseMethod && typeof node.key === "string")
|
|
||||||
base54.consider(node.key);
|
base54.consider(node.key);
|
||||||
else if (node instanceof AST_New)
|
else if (node instanceof AST_New)
|
||||||
base54.consider("new");
|
base54.consider("new");
|
||||||
else if (node instanceof AST_This)
|
else if (node instanceof AST_This)
|
||||||
base54.consider("this");
|
base54.consider("this");
|
||||||
else if (node instanceof AST_Super)
|
|
||||||
base54.consider("super");
|
|
||||||
else if (node instanceof AST_Try)
|
else if (node instanceof AST_Try)
|
||||||
base54.consider("try");
|
base54.consider("try");
|
||||||
else if (node instanceof AST_Catch)
|
else if (node instanceof AST_Catch)
|
||||||
base54.consider("catch");
|
base54.consider("catch");
|
||||||
else if (node instanceof AST_Finally)
|
else if (node instanceof AST_Finally)
|
||||||
base54.consider("finally");
|
base54.consider("finally");
|
||||||
else if (node instanceof AST_Yield)
|
|
||||||
base54.consider("yield");
|
|
||||||
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
||||||
base54.consider(node.name);
|
base54.consider(node.name);
|
||||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
||||||
|
|||||||
@@ -163,18 +163,10 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
if (self.value) self.value = self.value.transform(tw);
|
if (self.value) self.value = self.value.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Destructuring, function(self, tw) {
|
|
||||||
self.names = do_list(self.names, tw);
|
|
||||||
});
|
|
||||||
|
|
||||||
_(AST_Lambda, function(self, tw){
|
_(AST_Lambda, function(self, tw){
|
||||||
if (self.name) self.name = self.name.transform(tw);
|
if (self.name) self.name = self.name.transform(tw);
|
||||||
self.argnames = do_list(self.argnames, tw);
|
self.argnames = do_list(self.argnames, tw);
|
||||||
if (self.body instanceof AST_Node) {
|
self.body = do_list(self.body, tw);
|
||||||
self.body = self.body.transform(tw);
|
|
||||||
} else {
|
|
||||||
self.body = do_list(self.body, tw);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Call, function(self, tw){
|
_(AST_Call, function(self, tw){
|
||||||
@@ -195,10 +187,6 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.property = self.property.transform(tw);
|
self.property = self.property.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Yield, function(self, tw){
|
|
||||||
if (self.expression) self.expression = self.expression.transform(tw);
|
|
||||||
});
|
|
||||||
|
|
||||||
_(AST_Unary, function(self, tw){
|
_(AST_Unary, function(self, tw){
|
||||||
self.expression = self.expression.transform(tw);
|
self.expression = self.expression.transform(tw);
|
||||||
});
|
});
|
||||||
@@ -223,32 +211,7 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
});
|
});
|
||||||
|
|
||||||
_(AST_ObjectProperty, function(self, tw){
|
_(AST_ObjectProperty, function(self, tw){
|
||||||
if (self.key instanceof AST_Node) {
|
|
||||||
self.key = self.key.transform(tw);
|
|
||||||
}
|
|
||||||
self.value = self.value.transform(tw);
|
self.value = self.value.transform(tw);
|
||||||
});
|
});
|
||||||
|
|
||||||
_(AST_Class, function(self, tw){
|
|
||||||
if (self.name) self.name = self.name.transform(tw);
|
|
||||||
if (self.extends) self.extends = self.extends.transform(tw);
|
|
||||||
self.properties = do_list(self.properties, tw);
|
|
||||||
});
|
|
||||||
|
|
||||||
_(AST_Expansion, function(self, tw){
|
|
||||||
self.expression = self.expression.transform(tw);
|
|
||||||
});
|
|
||||||
|
|
||||||
_(AST_TemplateString, function(self, tw) {
|
|
||||||
for (var i = 0; i < self.segments.length; i++) {
|
|
||||||
if (!(self.segments[i] instanceof AST_TemplateSegment)) {
|
|
||||||
self.segments[i] = self.segments[i].transform(tw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_(AST_PrefixedTemplateString, function(self, tw) {
|
|
||||||
self.template_string = self.template_string.transform(tw);
|
|
||||||
});
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
22
package.json
22
package.json
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "uglify-es",
|
"name": "uglify-js",
|
||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"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.2",
|
"version": "3.0.10",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -33,22 +33,12 @@
|
|||||||
"source-map": "~0.5.1"
|
"source-map": "~0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~0.6.0",
|
"acorn": "~5.0.3",
|
||||||
"escodegen": "~1.3.3",
|
"mocha": "~2.3.4",
|
||||||
"esfuzz": "~0.3.1",
|
"semver": "~5.3.0"
|
||||||
"estraverse": "~1.5.1",
|
|
||||||
"mocha": "~2.3.4"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"uglify-to-browserify": "~1.0.0"
|
|
||||||
},
|
|
||||||
"browserify": {
|
|
||||||
"transform": [
|
|
||||||
"uglify-to-browserify"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/run-tests.js"
|
"test": "node test/run-tests.js"
|
||||||
},
|
},
|
||||||
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
|
"keywords": ["uglify", "uglify-js", "minify", "minifier", "es5"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// NOTE trailing comma doesn't contribute to length of an array
|
|
||||||
// That also means the array changes length if previous element is a hole too and got cut off
|
|
||||||
holes_and_undefined: {
|
holes_and_undefined: {
|
||||||
input: {
|
input: {
|
||||||
w = [1,,];
|
w = [1,,];
|
||||||
@@ -93,79 +91,6 @@ constant_join_2: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spread_with_variable_as_last_element: {
|
|
||||||
input: {
|
|
||||||
var values = [4, 5, 6];
|
|
||||||
var a = [1, 2, 3, ...values];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var values = [4, 5, 6];
|
|
||||||
var a = [1, 2, 3, ...values];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_variable_in_middle: {
|
|
||||||
input: {
|
|
||||||
var values = [4, 5, 6];
|
|
||||||
var a = [1, 2, 3, ...values, 7,,,];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var values = [4, 5, 6];
|
|
||||||
var a = [1, 2, 3, ...values, 7,,,];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_variable_at_front: {
|
|
||||||
input: {
|
|
||||||
var values = [1, 2, 3];
|
|
||||||
var a = [...values, 4, 5, 6];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var values = [1, 2, 3];
|
|
||||||
var a = [...values, 4, 5, 6];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_variable_at_front_after_elisions: {
|
|
||||||
input: {
|
|
||||||
var values = [1, 2, 3];
|
|
||||||
var a = [,,,...values, 4, 5, 6];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var values = [1, 2, 3];
|
|
||||||
var a = [,,,...values, 4, 5, 6];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_array_at_end: {
|
|
||||||
input: {
|
|
||||||
var a = [1, 2, ...[4, 5, 6]];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = [1, 2, ...[4, 5, 6]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_logical_expression_at_end: {
|
|
||||||
options = { evaluate: true }
|
|
||||||
input: {
|
|
||||||
var a = [1, 2, 3, ...[2+2]]
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = [1, 2, 3, ...[4]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spread_with_logical_expression_at_middle: {
|
|
||||||
options = { evaluate: true }
|
|
||||||
input: {
|
|
||||||
var a = [1, 1, ...[1+1, 1+2, 2+3], 8]
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = [1, 1, ...[2, 3, 5], 8]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constant_join_3: {
|
constant_join_3: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
arrow_functions_without_body: {
|
|
||||||
input: {
|
|
||||||
var a1 = () => 42;
|
|
||||||
var a2 = (p) => p;
|
|
||||||
var a3 = p => p;
|
|
||||||
var a4 = (...p) => p;
|
|
||||||
var a5 = (b, c) => b + c;
|
|
||||||
var a6 = (b, ...c) => b + c[0];
|
|
||||||
var a7 = (...b) => b.join();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a1 = () => 42;
|
|
||||||
var a2 = (p) => p;
|
|
||||||
var a3 = p => p;
|
|
||||||
var a4 = (...p) => p;
|
|
||||||
var a5 = (b, c) => b + c;
|
|
||||||
var a6 = (b, ...c) => b + c[0];
|
|
||||||
var a7 = (...b) => b.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_functions_with_body: {
|
|
||||||
input: {
|
|
||||||
var a1 = () => {
|
|
||||||
var a = 42 * Math.random();
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a2 = (p) => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a3 = p => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a4 = (...p) => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a5 = (b, c) => {
|
|
||||||
var result = b * c + b / c;
|
|
||||||
return result
|
|
||||||
};
|
|
||||||
var a6 = (b, ...c) => {
|
|
||||||
var result = b;
|
|
||||||
for (var i = 0; i < c.length; i++)
|
|
||||||
result += c[i];
|
|
||||||
return result
|
|
||||||
};
|
|
||||||
var a7 = (...b) => {
|
|
||||||
b.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a1 = () => {
|
|
||||||
var a = 42 * Math.random();
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a2 = (p) => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a3 = p => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a4 = (...p) => {
|
|
||||||
var a = Math.random() * p;
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
var a5 = (b, c) => {
|
|
||||||
var result = b * c + b / c;
|
|
||||||
return result
|
|
||||||
};
|
|
||||||
var a6 = (b, ...c) => {
|
|
||||||
var result = b;
|
|
||||||
for (var i = 0; i < c.length; i++)
|
|
||||||
result += c[i];
|
|
||||||
return result
|
|
||||||
};
|
|
||||||
var a7 = (...b) => {
|
|
||||||
b.join();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_function_with_single_parameter_with_default: {
|
|
||||||
input: {
|
|
||||||
var foo = (a = 0) => doSomething(a);
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=(a=0)=>doSomething(a);"
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_binding_pattern: {
|
|
||||||
input: {
|
|
||||||
var foo = ([]) => "foo";
|
|
||||||
var bar = ({}) => "bar";
|
|
||||||
var with_default = (foo = "default") => foo;
|
|
||||||
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
|
|
||||||
var array_after_spread = (...[foo]) => foo;
|
|
||||||
var array_after_spread = (...{foo}) => foo;
|
|
||||||
var computed = ({ [compute()]: x }) => {};
|
|
||||||
var array_hole = ([, , ...x] = [1, 2]) => {};
|
|
||||||
var object_trailing_elision = ({foo,}) => {};
|
|
||||||
var spread_empty_array = (...[]) => "foo";
|
|
||||||
var spread_empty_object = (...{}) => "foo";
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = ([]) => "foo";
|
|
||||||
var bar = ({}) => "bar";
|
|
||||||
var with_default = (foo = "default") => foo;
|
|
||||||
var object_with_default = ({foo = "default", bar: baz = "default"}) => foo;
|
|
||||||
var array_after_spread = (...[foo]) => foo;
|
|
||||||
var array_after_spread = (...{foo}) => foo;
|
|
||||||
var computed = ({ [compute()]: x }) => {};
|
|
||||||
var array_hole = ([, , ...x] = [1, 2]) => {};
|
|
||||||
var object_trailing_elision = ({foo,}) => {};
|
|
||||||
var spread_empty_array = (...[]) => "foo";
|
|
||||||
var spread_empty_object = (...{}) => "foo";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_binding_pattern_strict: {
|
|
||||||
input: {
|
|
||||||
var foo = ([,]) => "foo";
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo=([,])=>"foo";'
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_with_regexp: {
|
|
||||||
input: {
|
|
||||||
num => /\d{11,14}/.test( num )
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
num => /\d{11,14}/.test( num )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
|
|
||||||
let_statement: {
|
|
||||||
input: {
|
|
||||||
let x = 6;
|
|
||||||
}
|
|
||||||
expect_exact: "let x=6;"
|
|
||||||
}
|
|
||||||
|
|
||||||
do_not_hoist_let: {
|
|
||||||
options = {
|
|
||||||
hoist_vars: true,
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
if (FOO) {
|
|
||||||
let let1;
|
|
||||||
let let2;
|
|
||||||
var var1;
|
|
||||||
var var2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x() {
|
|
||||||
var var1, var2;
|
|
||||||
if (FOO) {
|
|
||||||
let let1;
|
|
||||||
let let2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
do_not_remove_anon_blocks_if_they_have_decls: {
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
{
|
|
||||||
let x;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var x;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const y;
|
|
||||||
class Zee {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let y;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x(){
|
|
||||||
{
|
|
||||||
let x
|
|
||||||
}
|
|
||||||
var x;
|
|
||||||
{
|
|
||||||
const y;
|
|
||||||
class Zee {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let y
|
|
||||||
}
|
|
||||||
var y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_unused_in_global_block: {
|
|
||||||
options = {
|
|
||||||
unused: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
{
|
|
||||||
let x;
|
|
||||||
const y;
|
|
||||||
class Zee {};
|
|
||||||
var w;
|
|
||||||
}
|
|
||||||
let ex;
|
|
||||||
const why;
|
|
||||||
class Zed {};
|
|
||||||
var wut;
|
|
||||||
console.log(x, y, Zee);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var w;
|
|
||||||
let ex;
|
|
||||||
const why;
|
|
||||||
class Zed {};
|
|
||||||
var wut;
|
|
||||||
console.log(x, y, Zee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regression_block_scope_resolves: {
|
|
||||||
mangle = { };
|
|
||||||
options = {
|
|
||||||
dead_code: false
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
(function () {
|
|
||||||
if(1) {
|
|
||||||
let x;
|
|
||||||
const y;
|
|
||||||
class Zee {};
|
|
||||||
}
|
|
||||||
if(1) {
|
|
||||||
let ex;
|
|
||||||
const why;
|
|
||||||
class Zi {};
|
|
||||||
}
|
|
||||||
console.log(x, y, Zee, ex, why, Zi);
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
(function () {
|
|
||||||
if (1) {
|
|
||||||
let o;
|
|
||||||
const n;
|
|
||||||
class c {};
|
|
||||||
}
|
|
||||||
if (1) {
|
|
||||||
let o;
|
|
||||||
const n;
|
|
||||||
class c {};
|
|
||||||
}
|
|
||||||
console.log(x, y, Zee, ex, why, Zi);
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_block_scope_mangler: {
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
var fn = function(code) {
|
|
||||||
switch (code) {
|
|
||||||
case 1:
|
|
||||||
let apple = code + 1;
|
|
||||||
let dog = code + 4;
|
|
||||||
console.log(apple, dog);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
let banana = code + 2;
|
|
||||||
console.log(banana);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
let cat = code + 3;
|
|
||||||
console.log(cat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var fn = function(o) {
|
|
||||||
switch (o) {
|
|
||||||
case 1:
|
|
||||||
let e = o + 1
|
|
||||||
let c = o + 4;
|
|
||||||
console.log(e, c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
let l = o + 2;
|
|
||||||
console.log(l);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
let a = o + 3;
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -583,8 +583,8 @@ collapse_vars_assignment: {
|
|||||||
return a = a;
|
return a = a;
|
||||||
}
|
}
|
||||||
function f1(c) {
|
function f1(c) {
|
||||||
const a = 3 / c;
|
var a = 3 / c;
|
||||||
const b = 1 - a;
|
var b = 1 - a;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
function f2(c) {
|
function f2(c) {
|
||||||
@@ -724,10 +724,10 @@ collapse_vars_misc1: {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
function f1(x) { var y = 5 - x; return y; }
|
function f1(x) { var y = 5 - x; return y; }
|
||||||
function f2(x) { const z = foo(), y = z / (5 - x); return y; }
|
function f2(x) { var z = foo(), y = z / (5 - x); return y; }
|
||||||
function f3(x) { var z = foo(), y = (5 - x) / z; return y; }
|
function f3(x) { var z = foo(), y = (5 - x) / z; return y; }
|
||||||
function f4(x) { var z = foo(), y = (5 - u) / z; return y; }
|
function f4(x) { var z = foo(), y = (5 - u) / z; return y; }
|
||||||
function f5(x) { const z = foo(), y = (5 - window.x) / z; return y; }
|
function f5(x) { var z = foo(), y = (5 - window.x) / z; return y; }
|
||||||
function f6() { var b = window.a * window.z; return b && zap(); }
|
function f6() { var b = window.a * window.z; return b && zap(); }
|
||||||
function f7() { var b = window.a * window.z; return b + b; }
|
function f7() { var b = window.a * window.z; return b + b; }
|
||||||
function f8() { var b = window.a * window.z; var c = b + 5; return b + c; }
|
function f8() { var b = window.a * window.z; var c = b + 5; return b + c; }
|
||||||
@@ -744,7 +744,7 @@ collapse_vars_misc1: {
|
|||||||
function f2(x) { return foo() / (5 - x) }
|
function f2(x) { return foo() / (5 - x) }
|
||||||
function f3(x) { return (5 - x) / foo() }
|
function f3(x) { return (5 - x) / foo() }
|
||||||
function f4(x) { var z = foo(); return (5 - u) / z }
|
function f4(x) { var z = foo(); return (5 - u) / z }
|
||||||
function f5(x) { const z = foo(); return (5 - window.x) / z }
|
function f5(x) { var z = foo(); return (5 - window.x) / z }
|
||||||
function f6() { return window.a * window.z && zap() }
|
function f6() { return window.a * window.z && zap() }
|
||||||
function f7() { var b = window.a * window.z; return b + b }
|
function f7() { var b = window.a * window.z; return b + b }
|
||||||
function f8() { var b = window.a * window.z; return b + (b + 5) }
|
function f8() { var b = window.a * window.z; return b + (b + 5) }
|
||||||
@@ -1328,7 +1328,6 @@ collapse_vars_regexp: {
|
|||||||
issue_1537: {
|
issue_1537: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var k = '';
|
var k = '';
|
||||||
@@ -1340,104 +1339,6 @@ issue_1537: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1537_for_of: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var k = '';
|
|
||||||
for (k of {prop: 'val'}){}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var k = '';
|
|
||||||
for (k of {prop: 'val'});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1537_destructuring_1: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
[x] = [y];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
[x] = [y];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1537_destructuring_2: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var x = foo();
|
|
||||||
[x] = [1];
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var x = foo();
|
|
||||||
[x] = [1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1537_destructuring_3: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var x = Math.random();
|
|
||||||
({p: x = 9} = {v: 1});
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var x = Math.random();
|
|
||||||
({p: x = 9} = {v: 1});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1537_destructuring_for_in: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
(function() {
|
|
||||||
for ([[x], y] in a);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
(function() {
|
|
||||||
for ([[x], y] in a);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1537_destructuring_for_of: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
toplevel: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
(function() {
|
|
||||||
for ([[x], y] of a);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var x = 1, y = 2;
|
|
||||||
(function() {
|
|
||||||
for ([[x], y] of a);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1562: {
|
issue_1562: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -2203,10 +2104,11 @@ unused_orig: {
|
|||||||
expect: {
|
expect: {
|
||||||
var a = 1;
|
var a = 1;
|
||||||
console.log(function(b) {
|
console.log(function(b) {
|
||||||
var a;
|
|
||||||
var c = b;
|
var c = b;
|
||||||
for (var d in c)
|
for (var d in c) {
|
||||||
return --b + (a = c[0]);
|
var a = c[0];
|
||||||
|
return --b + a;
|
||||||
|
}
|
||||||
a && a.NaN;
|
a && a.NaN;
|
||||||
}([2]), a);
|
}([2]), a);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,166 +0,0 @@
|
|||||||
issue_1191: {
|
|
||||||
options = {
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
comparisons : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
side_effects : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
sequences : false,
|
|
||||||
collapse_vars : false,
|
|
||||||
reduce_vars : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function foo(rot) {
|
|
||||||
const rotTol = 5;
|
|
||||||
if (rot < -rotTol || rot > rotTol)
|
|
||||||
bar();
|
|
||||||
baz();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo(rot) {
|
|
||||||
(rot < -5 || rot > 5) && bar();
|
|
||||||
baz();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1194: {
|
|
||||||
options = {
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
comparisons : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
side_effects : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
sequences : false,
|
|
||||||
collapse_vars : false,
|
|
||||||
reduce_vars : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f1() {const a = "X"; return a + a;}
|
|
||||||
function f2() {const aa = "X"; return aa + aa;}
|
|
||||||
function f3() {const aaa = "X"; return aaa + aaa;}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f1(){return"XX"}
|
|
||||||
function f2(){return"XX"}
|
|
||||||
function f3(){return"XX"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1396: {
|
|
||||||
options = {
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
comparisons : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
side_effects : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
sequences : false,
|
|
||||||
collapse_vars : false,
|
|
||||||
reduce_vars : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function foo(a) {
|
|
||||||
const VALUE = 1;
|
|
||||||
console.log(2 | VALUE);
|
|
||||||
console.log(VALUE + 1);
|
|
||||||
console.log(VALUE);
|
|
||||||
console.log(a & VALUE);
|
|
||||||
}
|
|
||||||
function bar() {
|
|
||||||
const s = "01234567890123456789";
|
|
||||||
console.log(s + s + s + s + s);
|
|
||||||
|
|
||||||
const CONSTANT = "abc";
|
|
||||||
console.log(CONSTANT + CONSTANT + CONSTANT + CONSTANT + CONSTANT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo(a) {
|
|
||||||
console.log(3);
|
|
||||||
console.log(2);
|
|
||||||
console.log(1);
|
|
||||||
console.log(1 & a);
|
|
||||||
}
|
|
||||||
function bar() {
|
|
||||||
const s = "01234567890123456789";
|
|
||||||
console.log(s + s + s + s + s);
|
|
||||||
|
|
||||||
console.log("abcabcabcabcabc");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unused_regexp_literal: {
|
|
||||||
options = {
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
comparisons : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
side_effects : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
sequences : false,
|
|
||||||
collapse_vars : false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f(){ var a = /b/; }
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f(){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regexp_literal_not_const: {
|
|
||||||
options = {
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
comparisons : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
side_effects : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
sequences : false,
|
|
||||||
collapse_vars : false,
|
|
||||||
reduce_vars : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
(function(){
|
|
||||||
var result;
|
|
||||||
const s = 'acdabcdeabbb';
|
|
||||||
const REGEXP_LITERAL = /ab*/g;
|
|
||||||
while (result = REGEXP_LITERAL.exec(s)) {
|
|
||||||
console.log(result[0]);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
(function() {
|
|
||||||
var result;
|
|
||||||
const REGEXP_LITERAL = /ab*/g;
|
|
||||||
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
@@ -90,153 +90,6 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
dead_code_block_decls_die: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
booleans : true,
|
|
||||||
evaluate : true
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
if (0) {
|
|
||||||
let foo = 6;
|
|
||||||
const bar = 12;
|
|
||||||
class Baz {};
|
|
||||||
var qux;
|
|
||||||
}
|
|
||||||
console.log(foo, bar, Baz);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var qux;
|
|
||||||
console.log(foo, bar, Baz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dead_code_const_declaration: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
loops : true,
|
|
||||||
booleans : true,
|
|
||||||
conditionals : true,
|
|
||||||
evaluate : true,
|
|
||||||
reduce_vars : true,
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var unused;
|
|
||||||
const CONST_FOO = false;
|
|
||||||
if (CONST_FOO) {
|
|
||||||
console.log("unreachable");
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var unused;
|
|
||||||
const CONST_FOO = !1;
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
dead_code_const_annotation: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
loops : true,
|
|
||||||
booleans : true,
|
|
||||||
conditionals : true,
|
|
||||||
evaluate : true,
|
|
||||||
reduce_vars : true,
|
|
||||||
toplevel : true,
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var unused;
|
|
||||||
/** @const */ var CONST_FOO_ANN = false;
|
|
||||||
if (CONST_FOO_ANN) {
|
|
||||||
console.log("unreachable");
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var unused;
|
|
||||||
var CONST_FOO_ANN = !1;
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
dead_code_const_annotation_regex: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
loops : true,
|
|
||||||
booleans : true,
|
|
||||||
conditionals : true,
|
|
||||||
evaluate : true
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var unused;
|
|
||||||
// @constraint this shouldn't be a constant
|
|
||||||
var CONST_FOO_ANN = false;
|
|
||||||
if (CONST_FOO_ANN) {
|
|
||||||
console.log("reachable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var unused;
|
|
||||||
var CONST_FOO_ANN = !1;
|
|
||||||
CONST_FOO_ANN && console.log('reachable');
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
dead_code_const_annotation_complex_scope: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
loops : true,
|
|
||||||
booleans : true,
|
|
||||||
conditionals : true,
|
|
||||||
evaluate : true,
|
|
||||||
reduce_vars : true,
|
|
||||||
toplevel : true,
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var unused_var;
|
|
||||||
/** @const */ var test = 'test';
|
|
||||||
// @const
|
|
||||||
var CONST_FOO_ANN = false;
|
|
||||||
var unused_var_2;
|
|
||||||
if (CONST_FOO_ANN) {
|
|
||||||
console.log("unreachable");
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
if (test === 'test') {
|
|
||||||
var beef = 'good';
|
|
||||||
/** @const */ var meat = 'beef';
|
|
||||||
var pork = 'bad';
|
|
||||||
if (meat === 'pork') {
|
|
||||||
console.log('also unreachable');
|
|
||||||
} else if (pork === 'good') {
|
|
||||||
console.log('reached, not const');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var unused_var;
|
|
||||||
var test = 'test';
|
|
||||||
var CONST_FOO_ANN = !1;
|
|
||||||
var unused_var_2;
|
|
||||||
var moo;
|
|
||||||
function bar() {}
|
|
||||||
var beef = 'good';
|
|
||||||
var meat = 'beef';
|
|
||||||
var pork = 'bad';
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
try_catch_finally: {
|
try_catch_finally: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -278,3 +131,19 @@ try_catch_finally: {
|
|||||||
"1",
|
"1",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accessor: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
get a() {},
|
||||||
|
set a(v){
|
||||||
|
this.b = 2;
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,332 +0,0 @@
|
|||||||
destructuring_arrays: {
|
|
||||||
input: {
|
|
||||||
{const [aa, bb] = cc;}
|
|
||||||
{const [aa, [bb, cc]] = dd;}
|
|
||||||
{let [aa, bb] = cc;}
|
|
||||||
{let [aa, [bb, cc]] = dd;}
|
|
||||||
var [aa, bb] = cc;
|
|
||||||
var [aa, [bb, cc]] = dd;
|
|
||||||
var [,[,,,,,],,,zz,] = xx; // Trailing comma
|
|
||||||
var [,,zzz,,] = xxx; // Trailing comma after hole
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
{const [aa, bb] = cc;}
|
|
||||||
{const [aa, [bb, cc]] = dd;}
|
|
||||||
{let [aa, bb] = cc;}
|
|
||||||
{let [aa, [bb, cc]] = dd;}
|
|
||||||
var [aa, bb] = cc;
|
|
||||||
var [aa, [bb, cc]] = dd;
|
|
||||||
var [,[,,,,,],,,zz] = xx;
|
|
||||||
var [,,zzz,,] = xxx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_arrays_holes: {
|
|
||||||
input: {
|
|
||||||
var [,,,,] = a;
|
|
||||||
var [,,b,] = c;
|
|
||||||
var [d,,] = e;
|
|
||||||
}
|
|
||||||
expect_exact: "var[,,,,]=a;var[,,b]=c;var[d,,]=e;"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_objects: {
|
|
||||||
input: {
|
|
||||||
{const {aa, bb} = {aa:1, bb:2};}
|
|
||||||
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
{let {aa, bb} = {aa:1, bb:2};}
|
|
||||||
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
var {aa, bb} = {aa:1, bb:2};
|
|
||||||
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
{const {aa, bb} = {aa:1, bb:2};}
|
|
||||||
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
{let {aa, bb} = {aa:1, bb:2};}
|
|
||||||
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
var {aa, bb} = {aa:1, bb:2};
|
|
||||||
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_objects_trailing_elision: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var {cc,} = foo;
|
|
||||||
}
|
|
||||||
expect_exact: "var{cc}=foo;"
|
|
||||||
}
|
|
||||||
|
|
||||||
nested_destructuring_objects: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
const [{a},b] = c;
|
|
||||||
let [{a},b] = c;
|
|
||||||
var [{a},b] = c;
|
|
||||||
}
|
|
||||||
expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;';
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_constdef_in_loops: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
for (const [x,y] in pairs);
|
|
||||||
for (const [a] = 0;;);
|
|
||||||
for (const {c} of cees);
|
|
||||||
}
|
|
||||||
expect_exact: "for(const[x,y]in pairs);for(const[a]=0;;);for(const{c}of cees);"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_letdef_in_loops: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
for (let [x,y] in pairs);
|
|
||||||
for (let [a] = 0;;);
|
|
||||||
for (let {c} of cees);
|
|
||||||
}
|
|
||||||
expect_exact: "for(let[x,y]in pairs);for(let[a]=0;;);for(let{c}of cees);"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_vardef_in_loops: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
for (var [x,y] in pairs);
|
|
||||||
for (var [a] = 0;;);
|
|
||||||
for (var {c} of cees);
|
|
||||||
}
|
|
||||||
expect_exact: "for(var[x,y]in pairs);for(var[a]=0;;);for(var{c}of cees);"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_expressions: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
({a, b});
|
|
||||||
[{a}];
|
|
||||||
f({x});
|
|
||||||
}
|
|
||||||
expect_exact: "({a,b});[{a}];f({x});"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_remove_unused_1: {
|
|
||||||
options = {
|
|
||||||
unused: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function a() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = [1];
|
|
||||||
var [b] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function b() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = {b: 1};
|
|
||||||
var {b} = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function c() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = [[1]];
|
|
||||||
var [[b]] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function d() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = {b: {b:1}};
|
|
||||||
var {b:{b}} = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function e() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = [1, 2, 3, 4, 5];
|
|
||||||
var x = [[1, 2, 3]];
|
|
||||||
var y = {h: 1};
|
|
||||||
var [b, ...c] = a;
|
|
||||||
var [...[e, f]] = x;
|
|
||||||
var [...{g: h}] = y;
|
|
||||||
f(b, c, e, f, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a() {
|
|
||||||
var a = [1];
|
|
||||||
var [b] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function b() {
|
|
||||||
var a = {b: 1};
|
|
||||||
var {b} = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function c() {
|
|
||||||
var a = [[1]];
|
|
||||||
var [[b]] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function d() {
|
|
||||||
var a = {b: {b:1}};
|
|
||||||
var {b:{b}} = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function e() {
|
|
||||||
var a = [1, 2, 3, 4, 5];
|
|
||||||
var x = [[1, 2, 3]];
|
|
||||||
var y = {h: 1};
|
|
||||||
var [b, ...c] = a;
|
|
||||||
var [...[e, f]] = x;
|
|
||||||
var [...{g: h}] = y;
|
|
||||||
f(b, c, e, f, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_remove_unused_2: {
|
|
||||||
options = {
|
|
||||||
unused: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function a() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = [,,1];
|
|
||||||
var [b] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function b() {
|
|
||||||
var unused = "foo";
|
|
||||||
var a = [{a: [1]}];
|
|
||||||
var [{b: a}] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a() {
|
|
||||||
var a = [,,1];
|
|
||||||
var [b] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
function b() {
|
|
||||||
var a = [{a: [1]}];
|
|
||||||
var [{b: a}] = a;
|
|
||||||
f(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object_destructuring_may_need_parentheses: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
({a, b} = {a: 1, b: 2});
|
|
||||||
}
|
|
||||||
expect_exact: "({a,b}={a:1,b:2});"
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_with_undefined_as_default_assignment: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
[foo = undefined] = bar;
|
|
||||||
[foo = void 0] = bar;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
[foo] = bar;
|
|
||||||
[foo] = bar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_dont_evaluate_with_undefined_as_default_assignment: {
|
|
||||||
options = {
|
|
||||||
evaluate: false
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
[foo = undefined] = bar;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
[foo = void 0] = bar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reduce_vars: {
|
|
||||||
options = {
|
|
||||||
reduce_vars: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
{const [aa, [bb, cc]] = dd;}
|
|
||||||
{let [aa, [bb, cc]] = dd;}
|
|
||||||
var [aa, [bb, cc]] = dd;
|
|
||||||
[aa, [bb, cc]] = dd;
|
|
||||||
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
|
|
||||||
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
|
|
||||||
const [{a},b] = c;
|
|
||||||
let [{a},b] = c;
|
|
||||||
var [{a},b] = c;
|
|
||||||
[{a},b] = c;
|
|
||||||
for (const [x,y] in pairs);
|
|
||||||
for (let [x,y] in pairs);
|
|
||||||
for (var [x,y] in pairs);
|
|
||||||
for ([x,y] in pairs);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
{const [aa, [bb, cc]] = dd;}
|
|
||||||
{let [aa, [bb, cc]] = dd;}
|
|
||||||
var [aa, [bb, cc]] = dd;
|
|
||||||
[aa, [bb, cc]] = dd;
|
|
||||||
{const {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
{let {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};}
|
|
||||||
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
|
|
||||||
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
|
|
||||||
const [{a},b] = c;
|
|
||||||
let [{a},b] = c;
|
|
||||||
var [{a},b] = c;
|
|
||||||
[{a},b] = c;
|
|
||||||
for (const [x,y] in pairs);
|
|
||||||
for (let [x,y] in pairs);
|
|
||||||
for (var [x,y] in pairs);
|
|
||||||
for ([x,y] in pairs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unused: {
|
|
||||||
options = {
|
|
||||||
unused: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
let { foo: [, , ...a] } = { foo: [1, 2, 3, 4], bar: 5 };
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1886: {
|
|
||||||
options = {
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
let [a] = [1];
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
let [a] = [1];
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
expect_exact: "1"
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
class_directives_compression: {
|
|
||||||
input: {
|
|
||||||
class foo {
|
|
||||||
foo() {
|
|
||||||
"use strict";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "class foo{foo(){}}"
|
|
||||||
}
|
|
||||||
@@ -164,87 +164,6 @@ used_var_in_catch: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unused_block_decls_in_catch: {
|
|
||||||
options = { unused: true };
|
|
||||||
input: {
|
|
||||||
function foo() {
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch(ex) {
|
|
||||||
let x = 10;
|
|
||||||
const y = 10;
|
|
||||||
class Zee {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo() {
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch(ex) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
used_block_decls_in_catch: {
|
|
||||||
options = { unused: true };
|
|
||||||
input: {
|
|
||||||
function foo() {
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch(ex) {
|
|
||||||
let x = 10;
|
|
||||||
const y = 10;
|
|
||||||
class Zee {};
|
|
||||||
}
|
|
||||||
console.log(x, y, Zee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo() {
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch(ex) {}
|
|
||||||
console.log(x, y, Zee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unused_block_decls: {
|
|
||||||
options = { unused: true };
|
|
||||||
input: {
|
|
||||||
function foo() {
|
|
||||||
{
|
|
||||||
const x;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let y;
|
|
||||||
}
|
|
||||||
console.log(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo() {
|
|
||||||
console.log(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unused_keep_harmony_destructuring: {
|
|
||||||
options = { unused: true };
|
|
||||||
input: {
|
|
||||||
function foo() {
|
|
||||||
var {x, y} = foo;
|
|
||||||
var a = foo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function foo() {
|
|
||||||
var {x, y} = foo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_fnames: {
|
keep_fnames: {
|
||||||
options = { unused: true, keep_fnames: true, unsafe: true };
|
options = { unused: true, keep_fnames: true, unsafe: true };
|
||||||
input: {
|
input: {
|
||||||
@@ -730,37 +649,6 @@ drop_value: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assign: {
|
|
||||||
options = {
|
|
||||||
evaluate: true,
|
|
||||||
reduce_vars: true,
|
|
||||||
unused: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f() {
|
|
||||||
const b = 2;
|
|
||||||
return 1 + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
const b = 2;
|
|
||||||
b = 3;
|
|
||||||
return 1 + b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
const b = 2;
|
|
||||||
b = 3;
|
|
||||||
return 1 + b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1539: {
|
issue_1539: {
|
||||||
options = {
|
options = {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
@@ -897,10 +785,6 @@ issue_1709: {
|
|||||||
var x = 1;
|
var x = 1;
|
||||||
return x;
|
return x;
|
||||||
}(),
|
}(),
|
||||||
function y() {
|
|
||||||
const y = 2;
|
|
||||||
return y;
|
|
||||||
}(),
|
|
||||||
function z() {
|
function z() {
|
||||||
function z() {}
|
function z() {}
|
||||||
return z;
|
return z;
|
||||||
@@ -913,10 +797,6 @@ issue_1709: {
|
|||||||
var x = 1;
|
var x = 1;
|
||||||
return x;
|
return x;
|
||||||
}(),
|
}(),
|
||||||
function() {
|
|
||||||
const y = 2;
|
|
||||||
return y;
|
|
||||||
}(),
|
|
||||||
function() {
|
function() {
|
||||||
function z() {}
|
function z() {}
|
||||||
return z;
|
return z;
|
||||||
|
|||||||
@@ -224,100 +224,6 @@ positive_zero: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
pow: {
|
|
||||||
options = { evaluate: true }
|
|
||||||
input: {
|
|
||||||
var a = 5 ** 3;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = 125;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_sequence: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var a = 2 ** 3 ** 2;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = 512;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_mixed: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var a = 5 + 2 ** 3 + 5;
|
|
||||||
var b = 5 * 3 ** 2;
|
|
||||||
var c = 5 ** 3 * 2;
|
|
||||||
var d = 5 ** +3;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = 18;
|
|
||||||
var b = 45;
|
|
||||||
var c = 250;
|
|
||||||
var d = 125;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_with_right_side_evaluating_to_unary: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var a = (4 - 7) ** foo;
|
|
||||||
var b = ++bar ** 3;
|
|
||||||
var c = --baz ** 2;
|
|
||||||
}
|
|
||||||
expect_exact: "var a=(-3)**foo;var b=++bar**3;var c=--baz**2;"
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_with_number_constants: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var a = 5 ** NaN;
|
|
||||||
/* NaN exponent results to NaN */
|
|
||||||
var b = 42 ** +0;
|
|
||||||
/* +0 exponent results to NaN */
|
|
||||||
var c = 42 ** -0;
|
|
||||||
/* -0 exponent results to NaN */
|
|
||||||
var d = NaN ** 1;
|
|
||||||
/* NaN with non-zero exponent is NaN */
|
|
||||||
var e = 2 ** Infinity;
|
|
||||||
/* abs(base) > 1 with Infinity as exponent is Infinity */
|
|
||||||
var f = 2 ** -Infinity;
|
|
||||||
/* abs(base) > 1 with -Infinity as exponent is +0 */
|
|
||||||
var g = (-7) ** (0.5);
|
|
||||||
var h = 2324334 ** 34343443;
|
|
||||||
var i = (-2324334) ** 34343443;
|
|
||||||
var j = 2 ** (-3);
|
|
||||||
var k = 2.0 ** -3;
|
|
||||||
var l = 2.0 ** (5 - 7);
|
|
||||||
var m = 3 ** -10; // Result will be 0.000016935087808430286, which is too long
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = NaN;
|
|
||||||
var b = 1;
|
|
||||||
var c = 1;
|
|
||||||
var d = NaN;
|
|
||||||
var e = 1/0;
|
|
||||||
var f = 0;
|
|
||||||
var g = NaN;
|
|
||||||
var h = 1/0;
|
|
||||||
var i = -1/0;
|
|
||||||
var j = .125;
|
|
||||||
var k = .125;
|
|
||||||
var l = .25;
|
|
||||||
var m = 3 ** -10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe_constant: {
|
unsafe_constant: {
|
||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
@@ -739,16 +645,17 @@ call_args: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const a = 1;
|
var a = 1;
|
||||||
console.log(a);
|
console.log(a);
|
||||||
+function(a) {
|
+function(a) {
|
||||||
return a;
|
return a;
|
||||||
}(a);
|
}(a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const a = 1;
|
var a = 1;
|
||||||
console.log(1);
|
console.log(1);
|
||||||
+(1, 1);
|
+(1, 1);
|
||||||
}
|
}
|
||||||
@@ -760,17 +667,17 @@ call_args_drop_param: {
|
|||||||
evaluate: true,
|
evaluate: true,
|
||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const a = 1;
|
var a = 1;
|
||||||
console.log(a);
|
console.log(a);
|
||||||
+function(a) {
|
+function(a) {
|
||||||
return a;
|
return a;
|
||||||
}(a, b);
|
}(a, b);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const a = 1;
|
|
||||||
console.log(1);
|
console.log(1);
|
||||||
+(b, 1);
|
+(b, 1);
|
||||||
}
|
}
|
||||||
@@ -1083,3 +990,50 @@ Infinity_NaN_undefined_LHS: {
|
|||||||
"}",
|
"}",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1964_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe_regexp: false,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "b"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1964_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe_regexp: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return "a b c".split(/\s/)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "b"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
expand_arguments: {
|
|
||||||
input: {
|
|
||||||
func(a, ...rest);
|
|
||||||
func(...all);
|
|
||||||
}
|
|
||||||
expect_exact: "func(a,...rest);func(...all);"
|
|
||||||
}
|
|
||||||
|
|
||||||
expand_expression_arguments: {
|
|
||||||
input: {
|
|
||||||
f(...a.b);
|
|
||||||
f(...a.b());
|
|
||||||
f(...(a));
|
|
||||||
f(...(a.b));
|
|
||||||
f(...a[i]);
|
|
||||||
}
|
|
||||||
expect_exact: "f(...a.b);f(...a.b());f(...a);f(...a.b);f(...a[i]);"
|
|
||||||
}
|
|
||||||
|
|
||||||
expand_parameters: {
|
|
||||||
input: {
|
|
||||||
(function (a, ...b){});
|
|
||||||
(function (...args){});
|
|
||||||
}
|
|
||||||
expect_exact: "(function(a,...b){});(function(...args){});"
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
pow: {
|
|
||||||
input: {
|
|
||||||
var a = 2 ** 7;
|
|
||||||
var b = 3;
|
|
||||||
b **= 2;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = 2 ** 7;
|
|
||||||
var b = 3;
|
|
||||||
b **= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_with_number_constants: {
|
|
||||||
input: {
|
|
||||||
var a = 5 ** NaN;
|
|
||||||
var b = 42 ** +0;
|
|
||||||
var c = 42 ** -0;
|
|
||||||
var d = NaN ** 1;
|
|
||||||
var e = 2 ** Infinity;
|
|
||||||
var f = 2 ** -Infinity;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = 5 ** NaN;
|
|
||||||
var b = 42 ** +0;
|
|
||||||
var c = 42 ** -0;
|
|
||||||
var d = NaN ** 1;
|
|
||||||
var e = 2 ** (1/0);
|
|
||||||
var f = 2 ** (-1/0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_with_parentheses: {
|
|
||||||
input: {
|
|
||||||
var g = (-7) ** (0.5);
|
|
||||||
var h = 2324334 ** 34343443;
|
|
||||||
var i = (-2324334) ** 34343443;
|
|
||||||
var j = 2 ** (-3);
|
|
||||||
var k = 2.0 ** -3;
|
|
||||||
var l = 2.0 ** (5 - 7);
|
|
||||||
}
|
|
||||||
expect_exact: "var g=(-7)**.5;var h=2324334**34343443;var i=(-2324334)**34343443;var j=2**-3;var k=2**-3;var l=2**(5-7);"
|
|
||||||
}
|
|
||||||
|
|
||||||
pow_with_unary_between_brackets: {
|
|
||||||
input: {
|
|
||||||
var a = (-(+5)) ** 3;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a = (-+5)**3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -120,7 +120,7 @@ mixed: {
|
|||||||
properties: true,
|
properties: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const FOO = { BAR: 0 };
|
var FOO = { BAR: 0 };
|
||||||
console.log(FOO.BAR);
|
console.log(FOO.BAR);
|
||||||
console.log(++CONFIG.DEBUG);
|
console.log(++CONFIG.DEBUG);
|
||||||
console.log(++CONFIG.VALUE);
|
console.log(++CONFIG.VALUE);
|
||||||
@@ -130,7 +130,7 @@ mixed: {
|
|||||||
console.log(CONFIG);
|
console.log(CONFIG);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const FOO = { BAR: 0 };
|
var FOO = { BAR: 0 };
|
||||||
console.log("moo");
|
console.log("moo");
|
||||||
console.log(++CONFIG.DEBUG);
|
console.log(++CONFIG.DEBUG);
|
||||||
console.log(++CONFIG.VALUE);
|
console.log(++CONFIG.VALUE);
|
||||||
|
|||||||
@@ -1,394 +0,0 @@
|
|||||||
arrow_function_parens: {
|
|
||||||
input: {
|
|
||||||
something && (() => {});
|
|
||||||
}
|
|
||||||
expect_exact: "something&&(()=>{});"
|
|
||||||
}
|
|
||||||
arrow_function_parens_2: {
|
|
||||||
input: {
|
|
||||||
(() => null)();
|
|
||||||
}
|
|
||||||
expect_exact: "(()=>null)();"
|
|
||||||
}
|
|
||||||
|
|
||||||
typeof_arrow_functions: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = typeof (x) => null;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=\"function\";"
|
|
||||||
}
|
|
||||||
|
|
||||||
classes: {
|
|
||||||
input: {
|
|
||||||
class SomeClass {
|
|
||||||
constructor() {
|
|
||||||
};
|
|
||||||
foo() {};
|
|
||||||
};
|
|
||||||
class NoSemi {
|
|
||||||
constructor(...args) {
|
|
||||||
}
|
|
||||||
foo() {}
|
|
||||||
};
|
|
||||||
class ChildClass extends SomeClass {};
|
|
||||||
var asExpression = class AsExpression {};
|
|
||||||
var nameless = class {};
|
|
||||||
}
|
|
||||||
expect_exact: "class SomeClass{constructor(){}foo(){}}class NoSemi{constructor(...args){}foo(){}}class ChildClass extends SomeClass{}var asExpression=class AsExpression{};var nameless=class{};"
|
|
||||||
}
|
|
||||||
|
|
||||||
class_statics: {
|
|
||||||
input: {
|
|
||||||
x = class {
|
|
||||||
static staticMethod() {}
|
|
||||||
static get foo() {}
|
|
||||||
static set bar() {}
|
|
||||||
static() { /* "static" can be a method name! */ }
|
|
||||||
get() { /* "get" can be a method name! */ }
|
|
||||||
set() { /* "set" can be a method name! */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "x=class{static staticMethod(){}static get foo(){}static set bar(){}static(){}get(){}set(){}};"
|
|
||||||
}
|
|
||||||
|
|
||||||
class_name_can_be_mangled: {
|
|
||||||
mangle = { };
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
class Foo {
|
|
||||||
}
|
|
||||||
var class1 = Foo
|
|
||||||
var class2 = class Bar {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x() {
|
|
||||||
class a { }
|
|
||||||
var n = a
|
|
||||||
var r = class a {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class_name_can_be_preserved: {
|
|
||||||
mangle = {
|
|
||||||
keep_classnames: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
(class Baz { });
|
|
||||||
class Foo {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x() {
|
|
||||||
(class Baz { });
|
|
||||||
class Foo {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
classes_can_have_generators: {
|
|
||||||
input: {
|
|
||||||
class Foo {
|
|
||||||
*bar() {}
|
|
||||||
static *baz() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
class Foo {
|
|
||||||
*bar() {}
|
|
||||||
static *baz() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
classes_can_have_computed_generators: {
|
|
||||||
input: {
|
|
||||||
class C4 {
|
|
||||||
*['constructor']() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
class C4 {
|
|
||||||
*['constructor']() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
classes_can_have_computed_static: {
|
|
||||||
input: {
|
|
||||||
class C4 {
|
|
||||||
static ['constructor']() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
class C4 {
|
|
||||||
static ['constructor']() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class_methods_and_getters_with_keep_quoted_props_enabled: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3,
|
|
||||||
keep_quoted_props: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
class clss {
|
|
||||||
a() {}
|
|
||||||
"b"() {}
|
|
||||||
get c() { return "c"}
|
|
||||||
get "d"() { return "d"}
|
|
||||||
set e(a) { doSomething(a); }
|
|
||||||
set 'f'(a) { doSomething(b); }
|
|
||||||
static g() {}
|
|
||||||
static "h"() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'class clss{a(){}"b"(){}get c(){return"c"}get"d"(){return"d"}set e(a){doSomething(a)}set\'f\'(a){doSomething(b)}static g(){}static"h"(){}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
classes_with_expression_as_expand: {
|
|
||||||
input: {
|
|
||||||
class D extends (calls++, C) {}
|
|
||||||
}
|
|
||||||
expect_exact: "class D extends(calls++,C){}"
|
|
||||||
}
|
|
||||||
|
|
||||||
new_target: {
|
|
||||||
input: {
|
|
||||||
new.target;
|
|
||||||
new.target.name;
|
|
||||||
}
|
|
||||||
expect_exact: "new.target;new.target.name;"
|
|
||||||
}
|
|
||||||
|
|
||||||
number_literals: {
|
|
||||||
input: {
|
|
||||||
0b1001;
|
|
||||||
0B1001;
|
|
||||||
0o11;
|
|
||||||
0O11;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect: {
|
|
||||||
9;
|
|
||||||
9;
|
|
||||||
9;
|
|
||||||
9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
import_statement: {
|
|
||||||
input: {
|
|
||||||
import "mod-name";
|
|
||||||
import Foo from "bar";
|
|
||||||
import { Bar, Baz } from 'lel';
|
|
||||||
import Bar, { Foo } from 'lel';
|
|
||||||
import { Bar as kex, Baz as food } from 'lel';
|
|
||||||
}
|
|
||||||
expect_exact: 'import"mod-name";import Foo from"bar";import{Bar,Baz}from"lel";import Bar,{Foo}from"lel";import{Bar as kex,Baz as food}from"lel";'
|
|
||||||
}
|
|
||||||
|
|
||||||
import_all_statement: {
|
|
||||||
input: {
|
|
||||||
import * from 'lel';
|
|
||||||
import * as Lel from 'lel';
|
|
||||||
}
|
|
||||||
expect_exact: 'import*from"lel";import*as Lel from"lel";'
|
|
||||||
}
|
|
||||||
|
|
||||||
export_statement: {
|
|
||||||
input: {
|
|
||||||
export default 1;
|
|
||||||
export var foo = 4;
|
|
||||||
export let foo = 6;
|
|
||||||
export const foo = 6;
|
|
||||||
export function foo() {};
|
|
||||||
export class foo { };
|
|
||||||
}
|
|
||||||
expect_exact: "export default 1;export var foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};"
|
|
||||||
}
|
|
||||||
|
|
||||||
export_module_statement: {
|
|
||||||
input: {
|
|
||||||
export * from "a.js";
|
|
||||||
export {A} from "a.js";
|
|
||||||
export {A, B} from "a.js";
|
|
||||||
export {C};
|
|
||||||
}
|
|
||||||
expect_exact: 'export*from"a.js";export{A}from"a.js";export{A,B}from"a.js";export{C};'
|
|
||||||
}
|
|
||||||
|
|
||||||
import_statement_mangling: {
|
|
||||||
mangle = { toplevel: true };
|
|
||||||
input: {
|
|
||||||
import Foo from "foo";
|
|
||||||
import Bar, {Food} from "lel";
|
|
||||||
import {What as Whatever} from "lel";
|
|
||||||
Foo();
|
|
||||||
Bar();
|
|
||||||
Food();
|
|
||||||
Whatever();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
import l from "foo";
|
|
||||||
import e, {Food as o} from "lel";
|
|
||||||
import {What as f} from "lel";
|
|
||||||
l();
|
|
||||||
e();
|
|
||||||
o();
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export_statement_mangling: {
|
|
||||||
mangle = { };
|
|
||||||
input: {
|
|
||||||
export var foo = 6;
|
|
||||||
export function bar() { }
|
|
||||||
export class Baz { }
|
|
||||||
bar(foo, Baz)
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
export var foo = 6;
|
|
||||||
export function bar() { }
|
|
||||||
export class Baz { }
|
|
||||||
bar(foo, Baz)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/1021
|
|
||||||
regression_for_of_const: {
|
|
||||||
input: {
|
|
||||||
for (const x of y) {}
|
|
||||||
for (const x in y) {}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
for (const x of y);for (const x in y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fabio: My patches accidentally caused a crash whenever
|
|
||||||
// there's an extraneous set of parens around an object.
|
|
||||||
regression_cannot_destructure: {
|
|
||||||
input: {
|
|
||||||
var x = ({ x : 3 });
|
|
||||||
x(({ x: 3 }));
|
|
||||||
}
|
|
||||||
expect_exact: "var x={x:3};x({x:3});";
|
|
||||||
}
|
|
||||||
|
|
||||||
regression_cannot_use_of: {
|
|
||||||
input: {
|
|
||||||
function of() {
|
|
||||||
}
|
|
||||||
var of = "is a valid variable name";
|
|
||||||
of = { of: "is ok" };
|
|
||||||
x.of;
|
|
||||||
of: foo()
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function of(){}
|
|
||||||
var of="is a valid variable name";
|
|
||||||
of={of:"is ok"};
|
|
||||||
x.of;
|
|
||||||
foo(); /* Label statement missing? No prob. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fat_arrow_as_param: {
|
|
||||||
input: {
|
|
||||||
foo(x => x);
|
|
||||||
foo(x => x, y => y);
|
|
||||||
|
|
||||||
foo(x => (x, x));
|
|
||||||
foo(x => (x, x), y => (y, y));
|
|
||||||
}
|
|
||||||
expect_exact: "foo(x=>x);foo(x=>x,y=>y);foo(x=>(x,x));foo(x=>(x,x),y=>(y,y));"
|
|
||||||
}
|
|
||||||
|
|
||||||
default_assign: {
|
|
||||||
options = {
|
|
||||||
keep_fargs: false,
|
|
||||||
unused: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f(a, b = 3) {
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
g = ([[] = 123]) => {};
|
|
||||||
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
|
|
||||||
|
|
||||||
function i([[x, y, z] = [4, 5, 6]] = []) {
|
|
||||||
console.log(b);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f(a) {
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
g = ([[] = 123]) => {};
|
|
||||||
h = ([[x, y, z] = [4, 5, 6]] = []) => {};
|
|
||||||
|
|
||||||
function i([[x, y, z] = [4, 5, 6]] = []) {
|
|
||||||
console.log(b);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expansion: {
|
|
||||||
options = {
|
|
||||||
keep_fargs: false,
|
|
||||||
unused: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f(a, ...b) {
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function f(a) {
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1613: {
|
|
||||||
mangle = { toplevel: true };
|
|
||||||
input: {
|
|
||||||
const name = 1;
|
|
||||||
const foo = {
|
|
||||||
name
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect_exact: "const n=1;const c={name:n};"
|
|
||||||
}
|
|
||||||
|
|
||||||
format_methods: {
|
|
||||||
beautify = {
|
|
||||||
beautify: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
class A extends B {constructor(a){x()} static s(b,c){y()} run(d,e,f){z()}}
|
|
||||||
}
|
|
||||||
expect_exact: [
|
|
||||||
"class A extends B {",
|
|
||||||
" constructor(a) {",
|
|
||||||
" x();",
|
|
||||||
" }",
|
|
||||||
" static s(b, c) {",
|
|
||||||
" y();",
|
|
||||||
" }",
|
|
||||||
" run(d, e, f) {",
|
|
||||||
" z();",
|
|
||||||
" }",
|
|
||||||
"}",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
|
|
||||||
hoist_vars: {
|
|
||||||
options = {
|
|
||||||
hoist_vars: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function a() {
|
|
||||||
bar();
|
|
||||||
var var1;
|
|
||||||
var var2;
|
|
||||||
}
|
|
||||||
function b(anArg) {
|
|
||||||
bar();
|
|
||||||
var var1;
|
|
||||||
var anArg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a() {
|
|
||||||
var var1, var2; // Vars go up and are joined
|
|
||||||
bar();
|
|
||||||
}
|
|
||||||
function b(anArg) {
|
|
||||||
var var1;
|
|
||||||
bar();
|
|
||||||
// But vars named like arguments go away!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hoist_funs: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function a() {
|
|
||||||
bar();
|
|
||||||
function foo() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a() {
|
|
||||||
function foo() {} // Funs go up
|
|
||||||
bar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hoist_no_destructurings: {
|
|
||||||
options = {
|
|
||||||
hoist_vars: true,
|
|
||||||
hoist_funs: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function a([anArg]) {
|
|
||||||
bar();
|
|
||||||
var var1;
|
|
||||||
var anArg; // Because anArg is already declared, this goes away!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a([anArg]) {
|
|
||||||
var var1;
|
|
||||||
bar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dont_hoist_var_destructurings: {
|
|
||||||
options = {
|
|
||||||
hoist_vars: true,
|
|
||||||
hoist_funs: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
// If foo is null or undefined, this should be an exception
|
|
||||||
var {x,y} = foo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x() {
|
|
||||||
var {x,y} = foo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -53,12 +53,3 @@ html_comment_in_string_literal: {
|
|||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
|
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
|
||||||
}
|
}
|
||||||
|
|
||||||
html_comment_after_multiline_comment: {
|
|
||||||
input: {
|
|
||||||
var foo; /*
|
|
||||||
*/--> var bar;
|
|
||||||
var foobar;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo;var foobar;"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -302,3 +302,25 @@ issue_1437_conditionals: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_512: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function a() {
|
||||||
|
if (b()) {
|
||||||
|
c();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {
|
||||||
|
if (!b()) throw e;
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
parenthesis_strings_in_parenthesis: {
|
|
||||||
input: {
|
|
||||||
var foo = ('(');
|
|
||||||
a(')');
|
|
||||||
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo="(";a(")");'
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,3 @@
|
|||||||
const_declaration: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
};
|
|
||||||
|
|
||||||
input: {
|
|
||||||
const goog = goog || {};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
const goog = goog || {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const_pragma: {
|
const_pragma: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
issue_1043: {
|
|
||||||
options = {
|
|
||||||
side_effects: true
|
|
||||||
};
|
|
||||||
|
|
||||||
input: {
|
|
||||||
function* range(start = 0, end = null, step = 1) {
|
|
||||||
if (end == null) {
|
|
||||||
end = start;
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = start; i < end; i += step) {
|
|
||||||
yield i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expect: {
|
|
||||||
function* range(start = 0, end = null, step = 1) {
|
|
||||||
if (null == end) {
|
|
||||||
end = start;
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = start; i < end; i += step)
|
|
||||||
yield i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
issue_1044: {
|
|
||||||
options = { evaluate: true, conditionals: true };
|
|
||||||
input: {
|
|
||||||
const mixed = Base ? class extends Base {} : class {}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
const mixed = Base ? class extends Base {} : class {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
issue_1212_debug_false: {
|
|
||||||
options = {
|
|
||||||
global_defs : { DEBUG: false },
|
|
||||||
sequences : true,
|
|
||||||
properties : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
comparisons : true,
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
loops : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
keep_fargs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
cascade : true,
|
|
||||||
side_effects : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
class foo {
|
|
||||||
bar() {
|
|
||||||
if (DEBUG)
|
|
||||||
console.log("DEV");
|
|
||||||
else
|
|
||||||
console.log("PROD");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
new foo().bar();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
class foo{
|
|
||||||
bar() { console.log("PROD") }
|
|
||||||
}
|
|
||||||
(new foo).bar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1212_debug_true: {
|
|
||||||
options = {
|
|
||||||
global_defs : { DEBUG: true },
|
|
||||||
sequences : true,
|
|
||||||
properties : true,
|
|
||||||
dead_code : true,
|
|
||||||
conditionals : true,
|
|
||||||
comparisons : true,
|
|
||||||
evaluate : true,
|
|
||||||
booleans : true,
|
|
||||||
loops : true,
|
|
||||||
unused : true,
|
|
||||||
hoist_funs : true,
|
|
||||||
keep_fargs : true,
|
|
||||||
if_return : true,
|
|
||||||
join_vars : true,
|
|
||||||
cascade : true,
|
|
||||||
side_effects : true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
class foo {
|
|
||||||
bar() {
|
|
||||||
if (DEBUG)
|
|
||||||
console.log("DEV");
|
|
||||||
else
|
|
||||||
console.log("PROD");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
new foo().bar();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
class foo{
|
|
||||||
bar() { console.log("DEV") }
|
|
||||||
}
|
|
||||||
(new foo).bar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
same_variable_in_multiple_for_loop: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: true,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
let a = 100;
|
|
||||||
console.log(i, a);
|
|
||||||
for (let i = 0; i < 2; i++) {
|
|
||||||
console.log(i, a);
|
|
||||||
let c = 2;
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
for (let o = 0; o < 3; o++) {
|
|
||||||
let l = 100;
|
|
||||||
console.log(o, l);
|
|
||||||
for (let o = 0; o < 2; o++) {
|
|
||||||
console.log(o, l);
|
|
||||||
let c = 2;
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
same_variable_in_multiple_forOf: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: true,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let tmp of test) {
|
|
||||||
console.log(tmp);
|
|
||||||
let dd;
|
|
||||||
dd = [ "e", "f", "g" ];
|
|
||||||
for (let tmp of dd) {
|
|
||||||
console.log(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let o of test) {
|
|
||||||
console.log(o);
|
|
||||||
let e;
|
|
||||||
e = [ "e", "f", "g" ];
|
|
||||||
for (let o of e)
|
|
||||||
console.log(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
same_variable_in_multiple_forIn: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: false,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let tmp in test) {
|
|
||||||
console.log(tmp);
|
|
||||||
let dd;
|
|
||||||
dd = [ "e", "f", "g" ];
|
|
||||||
for (let tmp in test) {
|
|
||||||
console.log(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let o in test) {
|
|
||||||
console.log(o);
|
|
||||||
let e;
|
|
||||||
e = [ "e", "f", "g" ];
|
|
||||||
for (let o in test)
|
|
||||||
console.log(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
different_variable_in_multiple_for_loop: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: true,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
let a = 100;
|
|
||||||
console.log(i, a);
|
|
||||||
for (let j = 0; j < 2; j++) {
|
|
||||||
console.log(j, a);
|
|
||||||
let c = 2;
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
for (let o = 0; o < 3; o++) {
|
|
||||||
let l = 100;
|
|
||||||
console.log(o, l);
|
|
||||||
for (let o = 0; o < 2; o++) {
|
|
||||||
console.log(o, l);
|
|
||||||
let c = 2;
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
different_variable_in_multiple_forOf: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: true,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let tmp of test) {
|
|
||||||
console.log(tmp);
|
|
||||||
let dd;
|
|
||||||
dd = [ "e", "f", "g" ];
|
|
||||||
for (let t of dd) {
|
|
||||||
console.log(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let o of test) {
|
|
||||||
console.log(o);
|
|
||||||
let e;
|
|
||||||
e = [ "e", "f", "g" ];
|
|
||||||
for (let o of e)
|
|
||||||
console.log(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
different_variable_in_multiple_forIn: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: false,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let tmp in test) {
|
|
||||||
console.log(tmp);
|
|
||||||
let dd;
|
|
||||||
dd = [ "e", "f", "g" ];
|
|
||||||
for (let t in test) {
|
|
||||||
console.log(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var test = [ "a", "b", "c" ];
|
|
||||||
for (let o in test) {
|
|
||||||
console.log(o);
|
|
||||||
let e;
|
|
||||||
e = [ "e", "f", "g" ];
|
|
||||||
for (let o in test)
|
|
||||||
console.log(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
more_variable_in_multiple_for: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
|
||||||
loops: true,
|
|
||||||
unused: false,
|
|
||||||
keep_fargs: true,
|
|
||||||
if_return: true,
|
|
||||||
join_vars: true,
|
|
||||||
cascade: true,
|
|
||||||
side_effects: true,
|
|
||||||
collapse_vars: true,
|
|
||||||
}
|
|
||||||
mangle = {}
|
|
||||||
input: {
|
|
||||||
for (let a = 9, i = 0; i < 20; i += a) {
|
|
||||||
let b = a++ + i;
|
|
||||||
console.log(a, b, i);
|
|
||||||
for (let k = b, m = b*b, i = 0; i < 10; i++) {
|
|
||||||
console.log(a, b, m, k, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
for (let o = 9, l = 0; l < 20; l += o) {
|
|
||||||
let c = o++ + l;
|
|
||||||
console.log(o, c, l);
|
|
||||||
for (let l = c, e = c * c, f = 0; f < 10; f++)
|
|
||||||
console.log(o, c, e, l, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
@@ -85,15 +85,3 @@ unsafe_undefined: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime_error: {
|
|
||||||
input: {
|
|
||||||
const a = 1;
|
|
||||||
console.log(a++);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
const a = 1;
|
|
||||||
console.log(a++);
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -103,3 +103,137 @@ numeric_literal: {
|
|||||||
"8 7 8",
|
"8 7 8",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
identifier: {
|
||||||
|
mangle_props = {}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
abstract: 1,
|
||||||
|
boolean: 2,
|
||||||
|
byte: 3,
|
||||||
|
char: 4,
|
||||||
|
class: 5,
|
||||||
|
double: 6,
|
||||||
|
enum: 7,
|
||||||
|
export: 8,
|
||||||
|
extends: 9,
|
||||||
|
final: 10,
|
||||||
|
float: 11,
|
||||||
|
goto: 12,
|
||||||
|
implements: 13,
|
||||||
|
import: 14,
|
||||||
|
int: 15,
|
||||||
|
interface: 16,
|
||||||
|
let: 17,
|
||||||
|
long: 18,
|
||||||
|
native: 19,
|
||||||
|
package: 20,
|
||||||
|
private: 21,
|
||||||
|
protected: 22,
|
||||||
|
public: 23,
|
||||||
|
short: 24,
|
||||||
|
static: 25,
|
||||||
|
super: 26,
|
||||||
|
synchronized: 27,
|
||||||
|
this: 28,
|
||||||
|
throws: 29,
|
||||||
|
transient: 30,
|
||||||
|
volatile: 31,
|
||||||
|
yield: 32,
|
||||||
|
false: 33,
|
||||||
|
null: 34,
|
||||||
|
true: 35,
|
||||||
|
break: 36,
|
||||||
|
case: 37,
|
||||||
|
catch: 38,
|
||||||
|
const: 39,
|
||||||
|
continue: 40,
|
||||||
|
debugger: 41,
|
||||||
|
default: 42,
|
||||||
|
delete: 43,
|
||||||
|
do: 44,
|
||||||
|
else: 45,
|
||||||
|
finally: 46,
|
||||||
|
for: 47,
|
||||||
|
function: 48,
|
||||||
|
if: 49,
|
||||||
|
in: 50,
|
||||||
|
instanceof: 51,
|
||||||
|
new: 52,
|
||||||
|
return: 53,
|
||||||
|
switch: 54,
|
||||||
|
throw: 55,
|
||||||
|
try: 56,
|
||||||
|
typeof: 57,
|
||||||
|
var: 58,
|
||||||
|
void: 59,
|
||||||
|
while: 60,
|
||||||
|
with: 61,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
d: 4,
|
||||||
|
e: 5,
|
||||||
|
f: 6,
|
||||||
|
g: 7,
|
||||||
|
h: 8,
|
||||||
|
i: 9,
|
||||||
|
j: 10,
|
||||||
|
k: 11,
|
||||||
|
l: 12,
|
||||||
|
m: 13,
|
||||||
|
n: 14,
|
||||||
|
o: 15,
|
||||||
|
p: 16,
|
||||||
|
q: 17,
|
||||||
|
r: 18,
|
||||||
|
s: 19,
|
||||||
|
t: 20,
|
||||||
|
u: 21,
|
||||||
|
v: 22,
|
||||||
|
w: 23,
|
||||||
|
x: 24,
|
||||||
|
y: 25,
|
||||||
|
z: 26,
|
||||||
|
A: 27,
|
||||||
|
B: 28,
|
||||||
|
C: 29,
|
||||||
|
D: 30,
|
||||||
|
F: 31,
|
||||||
|
G: 32,
|
||||||
|
false: 33,
|
||||||
|
null: 34,
|
||||||
|
true: 35,
|
||||||
|
H: 36,
|
||||||
|
I: 37,
|
||||||
|
J: 38,
|
||||||
|
K: 39,
|
||||||
|
L: 40,
|
||||||
|
M: 41,
|
||||||
|
N: 42,
|
||||||
|
O: 43,
|
||||||
|
P: 44,
|
||||||
|
Q: 45,
|
||||||
|
R: 46,
|
||||||
|
S: 47,
|
||||||
|
T: 48,
|
||||||
|
U: 49,
|
||||||
|
V: 50,
|
||||||
|
W: 51,
|
||||||
|
X: 52,
|
||||||
|
Y: 53,
|
||||||
|
Z: 54,
|
||||||
|
$: 55,
|
||||||
|
_: 56,
|
||||||
|
aa: 57,
|
||||||
|
ba: 58,
|
||||||
|
ca: 59,
|
||||||
|
da: 60,
|
||||||
|
ea: 61,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
31
test/compress/issue-1943.js
Normal file
31
test/compress/issue-1943.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
operator: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
typeof
|
||||||
|
}
|
||||||
|
expect_exact: "a.typeof;"
|
||||||
|
}
|
||||||
|
|
||||||
|
name: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
b
|
||||||
|
}
|
||||||
|
expect_exact: "a.b;"
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
default
|
||||||
|
}
|
||||||
|
expect_exact: "a.default;"
|
||||||
|
}
|
||||||
|
|
||||||
|
atom: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
true
|
||||||
|
}
|
||||||
|
expect_exact: "a.true;"
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
|
|
||||||
compress_new_function: {
|
|
||||||
options = {
|
|
||||||
unsafe: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
new Function("aa, bb", 'return aa;');
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
Function("a", "b", "return a");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compress_new_function_with_destruct: {
|
|
||||||
options = {
|
|
||||||
unsafe: true,
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
new Function("aa, [bb]", 'return aa;');
|
|
||||||
new Function("aa, {bb}", 'return aa;');
|
|
||||||
new Function("[[aa]], [{bb}]", 'return aa;');
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
Function("a", "[b]", "return a");
|
|
||||||
Function("a", "{bb}", "return a");
|
|
||||||
Function("[[a]]", "[{bb}]", 'return a');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ mixed: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const ENV = 3;
|
var ENV = 3;
|
||||||
var FOO = 4;
|
var FOO = 4;
|
||||||
f(ENV * 10);
|
f(ENV * 10);
|
||||||
--FOO;
|
--FOO;
|
||||||
@@ -49,7 +49,7 @@ mixed: {
|
|||||||
x = DEBUG;
|
x = DEBUG;
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const ENV = 3;
|
var ENV = 3;
|
||||||
var FOO = 4;
|
var FOO = 4;
|
||||||
f(10);
|
f(10);
|
||||||
--FOO;
|
--FOO;
|
||||||
@@ -60,7 +60,7 @@ mixed: {
|
|||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,14]',
|
'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,12]',
|
||||||
'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]',
|
'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]',
|
||||||
'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]',
|
'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]',
|
||||||
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]',
|
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]',
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
template_strings: {
|
|
||||||
input: {
|
|
||||||
foo(
|
|
||||||
`<span>${contents}</span>`,
|
|
||||||
`<a href="${url}">${text}</a>`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
expect_exact: "foo(`<span>${contents}</span>`,`<a href=\"${url}\">${text}</a>`);"
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
only_vars: {
|
|
||||||
options = { join_vars: true };
|
|
||||||
input: {
|
|
||||||
let netmaskBinary = '';
|
|
||||||
for (let i = 0; i < netmaskBits; ++i) {
|
|
||||||
netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
let netmaskBinary = '';
|
|
||||||
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1079_with_vars: {
|
|
||||||
options = { join_vars: true };
|
|
||||||
input: {
|
|
||||||
var netmaskBinary = '';
|
|
||||||
for (var i = 0; i < netmaskBits; ++i) {
|
|
||||||
netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
for (var netmaskBinary = '', i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1079_with_mixed: {
|
|
||||||
options = { join_vars: true };
|
|
||||||
input: {
|
|
||||||
var netmaskBinary = '';
|
|
||||||
for (let i = 0; i < netmaskBits; ++i) {
|
|
||||||
netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var netmaskBinary = ''
|
|
||||||
for (let i = 0; i < netmaskBits; ++i) netmaskBinary += '1';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -146,50 +146,6 @@ parse_do_while_without_semicolon: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
keep_collapse_const_in_own_block_scope: {
|
|
||||||
options = {
|
|
||||||
join_vars: true,
|
|
||||||
loops: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var i=2;
|
|
||||||
const c=5;
|
|
||||||
while(i--)
|
|
||||||
console.log(i);
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var i=2;
|
|
||||||
const c=5;
|
|
||||||
for(;i--;)
|
|
||||||
console.log(i);
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_collapse_const_in_own_block_scope_2: {
|
|
||||||
options = {
|
|
||||||
join_vars: true,
|
|
||||||
loops: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
const c=5;
|
|
||||||
var i=2; // Moves to loop, while it did not in previous test
|
|
||||||
while(i--)
|
|
||||||
console.log(i);
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
const c=5;
|
|
||||||
for(var i=2;i--;)
|
|
||||||
console.log(i);
|
|
||||||
console.log(c);
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluate: {
|
evaluate: {
|
||||||
options = {
|
options = {
|
||||||
loops: true,
|
loops: true,
|
||||||
|
|||||||
@@ -82,19 +82,3 @@ new_with_unary_prefix: {
|
|||||||
}
|
}
|
||||||
expect_exact: 'var bar=(+new Date).toString(32);';
|
expect_exact: 'var bar=(+new Date).toString(32);';
|
||||||
}
|
}
|
||||||
|
|
||||||
new_with_assignement_expression: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var a;
|
|
||||||
new x(a = 5 * 2, b = [1, 2, 3], c = {a: "a", b: "b", cd: "c" + "d"});
|
|
||||||
new y([a, b] = [3, 4]);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a;
|
|
||||||
new x(a = 10, b = [1, 2, 3], c = {a: "a", b: "b", cd: "cd"});
|
|
||||||
new y([a, b] = [3, 4]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
12
test/compress/node_version.js
Normal file
12
test/compress/node_version.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
eval_let: {
|
||||||
|
input: {
|
||||||
|
eval("let a;");
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
eval("let a;");
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect_stdout: ""
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
@@ -1,512 +0,0 @@
|
|||||||
getter_setter: {
|
|
||||||
input: {
|
|
||||||
var get = "bar";
|
|
||||||
var a = {
|
|
||||||
get,
|
|
||||||
set: "foo",
|
|
||||||
get bar() {
|
|
||||||
return this.get;
|
|
||||||
},
|
|
||||||
get 5() {
|
|
||||||
return "five";
|
|
||||||
},
|
|
||||||
get 0xf55() {
|
|
||||||
return "f five five";
|
|
||||||
},
|
|
||||||
get "five"() {
|
|
||||||
return 5;
|
|
||||||
},
|
|
||||||
set one(value) {
|
|
||||||
this._one = value;
|
|
||||||
},
|
|
||||||
set 9(value) {
|
|
||||||
this._nine = value;
|
|
||||||
},
|
|
||||||
set 0b1010(value) {
|
|
||||||
this._ten = value;
|
|
||||||
},
|
|
||||||
set "eleven"(value) {
|
|
||||||
this._eleven = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var b = {
|
|
||||||
get() { return "gift"; },
|
|
||||||
set: function(code) { return "Storing code " + code; }
|
|
||||||
};
|
|
||||||
var c = {
|
|
||||||
["get"]: "foo",
|
|
||||||
["set"]: "bar"
|
|
||||||
};
|
|
||||||
var d = {
|
|
||||||
get: "foo",
|
|
||||||
set: "bar"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var get = "bar";
|
|
||||||
var a = {
|
|
||||||
get,
|
|
||||||
set: "foo",
|
|
||||||
get bar() {
|
|
||||||
return this.get;
|
|
||||||
},
|
|
||||||
get 5() {
|
|
||||||
return "five";
|
|
||||||
},
|
|
||||||
get 0xf55() {
|
|
||||||
return "f five five";
|
|
||||||
},
|
|
||||||
get "five"() {
|
|
||||||
return 5;
|
|
||||||
},
|
|
||||||
set one(value) {
|
|
||||||
this._one = value;
|
|
||||||
},
|
|
||||||
set 9(value) {
|
|
||||||
this._nine = value;
|
|
||||||
},
|
|
||||||
set 0b1010(value) {
|
|
||||||
this._ten = value;
|
|
||||||
},
|
|
||||||
set "eleven"(value) {
|
|
||||||
this._eleven = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var b = {
|
|
||||||
get() { return "gift"; },
|
|
||||||
set: function(code) { return "Storing code " + code; }
|
|
||||||
};
|
|
||||||
var c = {
|
|
||||||
["get"]: "foo",
|
|
||||||
["set"]: "bar"
|
|
||||||
};
|
|
||||||
var d = {
|
|
||||||
get: "foo",
|
|
||||||
set: "bar"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getter_setter_mangler: {
|
|
||||||
mangle = {}
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function f(get,set) {
|
|
||||||
return {
|
|
||||||
get,
|
|
||||||
set,
|
|
||||||
get g(){},
|
|
||||||
set s(n){},
|
|
||||||
c,
|
|
||||||
a:1,
|
|
||||||
m(){}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function f(n,t){return{get:n,set:t,get g(){},set s(n){},c,a:1,m(){}}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
use_shorthand_opportunity: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = 123;
|
|
||||||
var obj = {foo: foo};
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=123;var obj={foo};"
|
|
||||||
}
|
|
||||||
|
|
||||||
computed_property_names: {
|
|
||||||
input: {
|
|
||||||
obj({ ["x" + "x"]: 6 });
|
|
||||||
}
|
|
||||||
expect_exact: 'obj({["x"+"x"]:6});'
|
|
||||||
}
|
|
||||||
|
|
||||||
computed_property_names_evaluated_1: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
obj({
|
|
||||||
[1 + 1]: 2,
|
|
||||||
["x" + "x"]: 6
|
|
||||||
});
|
|
||||||
}
|
|
||||||
expect_exact: 'obj({[2]:2,["xx"]:6});'
|
|
||||||
}
|
|
||||||
|
|
||||||
computed_property_names_evaluated_2: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = something();
|
|
||||||
|
|
||||||
var obj = {
|
|
||||||
[foo]() {
|
|
||||||
return "blah";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo=something();var obj={[foo](){return"blah"}};'
|
|
||||||
}
|
|
||||||
|
|
||||||
shorthand_properties: {
|
|
||||||
mangle = true;
|
|
||||||
input: {
|
|
||||||
(function() {
|
|
||||||
var prop = 1;
|
|
||||||
const value = {prop};
|
|
||||||
return value;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
(function() {
|
|
||||||
var n = 1;
|
|
||||||
const r = {prop:n};
|
|
||||||
return r;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
x = {
|
|
||||||
foo(a, b) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y = {
|
|
||||||
foo([{a}]) {
|
|
||||||
return a;
|
|
||||||
},
|
|
||||||
bar(){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "x={foo(a,b){return x}};y={foo([{a}]){return a},bar(){}};"
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods_with_computed_property: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = {
|
|
||||||
[Symbol.iterator]() {
|
|
||||||
return { /* stuff */ }
|
|
||||||
},
|
|
||||||
[1 + 2]() {
|
|
||||||
return 3;
|
|
||||||
},
|
|
||||||
["1" + "4"]() {
|
|
||||||
return 14;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = {
|
|
||||||
[Symbol.iterator]() {
|
|
||||||
return { /* stuff */ }
|
|
||||||
},
|
|
||||||
[3]() {
|
|
||||||
return 3;
|
|
||||||
},
|
|
||||||
["14"]() {
|
|
||||||
return 14;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods_with_computed_property2: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = {
|
|
||||||
[[1]](){
|
|
||||||
return "success";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
doSomething(foo[[1]]());
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo={[[1]](){return"success"}};doSomething(foo[[1]]());'
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods_with_various_property_names: {
|
|
||||||
input: {
|
|
||||||
var get = "bar";
|
|
||||||
var a = {
|
|
||||||
bar() {
|
|
||||||
return this.get;
|
|
||||||
},
|
|
||||||
5() {
|
|
||||||
return "five";
|
|
||||||
},
|
|
||||||
0xf55() {
|
|
||||||
return "f five five";
|
|
||||||
},
|
|
||||||
"five"() {
|
|
||||||
return 5;
|
|
||||||
},
|
|
||||||
0b1010(value) {
|
|
||||||
this._ten = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var get = "bar";
|
|
||||||
var a = {
|
|
||||||
bar() {
|
|
||||||
return this.get;
|
|
||||||
},
|
|
||||||
5() {
|
|
||||||
return "five";
|
|
||||||
},
|
|
||||||
0xf55() {
|
|
||||||
return "f five five";
|
|
||||||
},
|
|
||||||
"five"() {
|
|
||||||
return 5;
|
|
||||||
},
|
|
||||||
0b1010(value) {
|
|
||||||
this._ten = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods_and_mangle_props: {
|
|
||||||
mangle_props = {
|
|
||||||
regex: /_/
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
function x() {
|
|
||||||
obj = {
|
|
||||||
_foo() { return 1; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function x() {
|
|
||||||
obj = {
|
|
||||||
a() { return 1; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_generators: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
x = {
|
|
||||||
*foo(a, b) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y = {
|
|
||||||
*foo([{a}]) {
|
|
||||||
yield a;
|
|
||||||
},
|
|
||||||
bar(){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "x={*foo(a,b){return x}};y={*foo([{a}]){yield a},bar(){}};"
|
|
||||||
}
|
|
||||||
|
|
||||||
concise_methods_and_keyword_names: {
|
|
||||||
input: {
|
|
||||||
x = {
|
|
||||||
catch() {},
|
|
||||||
throw() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
x={catch(){},throw(){}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getter_setter_with_computed_value: {
|
|
||||||
input: {
|
|
||||||
class C {
|
|
||||||
get ['a']() {
|
|
||||||
return 'A';
|
|
||||||
}
|
|
||||||
set ['a'](value) {
|
|
||||||
do_something(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var x = {
|
|
||||||
get [a.b]() {
|
|
||||||
return 42;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
class MyArray extends Array {
|
|
||||||
get [Symbol.species]() {
|
|
||||||
return Array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'class C{get["a"](){return"A"}set["a"](value){do_something(a)}}var x={get[a.b](){return 42}};class MyArray extends Array{get[Symbol.species](){return Array}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
property_with_operator_value: {
|
|
||||||
input: {
|
|
||||||
var foo = {
|
|
||||||
"*": 1,
|
|
||||||
get "*"() {
|
|
||||||
return 2;
|
|
||||||
},
|
|
||||||
*"*"() {
|
|
||||||
return 3;
|
|
||||||
},
|
|
||||||
"%": 1,
|
|
||||||
get "%"() {
|
|
||||||
return 2;
|
|
||||||
},
|
|
||||||
*"%"() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class bar {
|
|
||||||
get "*"() {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
*"*"() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
get "%"() {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
*"%"() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo={"*":1,get"*"(){return 2},*"*"(){return 3},"%":1,get"%"(){return 2},*"%"(){return 3}};class bar{get"*"(){return 1}*"*"(){return 2}get"%"(){return 1}*"%"(){return 2}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
property_with_unprintable: {
|
|
||||||
input: {
|
|
||||||
var foo = {
|
|
||||||
"\x00\x01": "foo",
|
|
||||||
get "\x00\x01"() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
set "\x00\x01"(foo) {
|
|
||||||
save(foo);
|
|
||||||
},
|
|
||||||
*"\x00\x01"() {
|
|
||||||
return "foobar";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class bar {
|
|
||||||
get "\x00\x01"() {
|
|
||||||
return "bar"
|
|
||||||
}
|
|
||||||
set "\x00\x01"(foo) {
|
|
||||||
save(foo);
|
|
||||||
}
|
|
||||||
*"\x00\x01"() {
|
|
||||||
return "foobar";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo={"\\0\x01":"foo",get"\\0\x01"(){return"bar"},set"\\0\x01"(foo){save(foo)},*"\\0\x01"(){return"foobar"}};class bar{get"\\0\x01"(){return"bar"}set"\\0\x01"(foo){save(foo)}*"\\0\x01"(){return"foobar"}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
property_with_unprintable_ascii_only: {
|
|
||||||
beautify = {
|
|
||||||
ascii_only: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = {
|
|
||||||
"\x00\x01": "foo",
|
|
||||||
get "\x00\x01"() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
set "\x00\x01"(foo) {
|
|
||||||
save(foo);
|
|
||||||
},
|
|
||||||
*"\x00\x01"() {
|
|
||||||
return "foobar";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class bar {
|
|
||||||
get "\x00\x01"() {
|
|
||||||
return "bar"
|
|
||||||
}
|
|
||||||
set "\x00\x01"(foo) {
|
|
||||||
save(foo);
|
|
||||||
}
|
|
||||||
*"\x00\x01"() {
|
|
||||||
return "foobar";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo={"\\0\\x01":"foo",get"\\0\\x01"(){return"bar"},set"\\0\\x01"(foo){save(foo)},*"\\0\\x01"(){return"foobar"}};class bar{get"\\0\\x01"(){return"bar"}set"\\0\\x01"(foo){save(foo)}*"\\0\\x01"(){return"foobar"}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
property_with_unprintable_ascii_only_static: {
|
|
||||||
beautify = {
|
|
||||||
ascii_only: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
class foo {
|
|
||||||
static get "\x02\x03"() {
|
|
||||||
return "bar";
|
|
||||||
}
|
|
||||||
static set "\x04\x05"(foo) {
|
|
||||||
save(foo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'class foo{static get"\\x02\\x03"(){return"bar"}static set"\\x04\\x05"(foo){save(foo)}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
methods_and_getters_with_keep_quoted_props_enabled: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3,
|
|
||||||
keep_quoted_props: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var obj = {
|
|
||||||
a() {},
|
|
||||||
"b"() {},
|
|
||||||
get c() { return "c"},
|
|
||||||
get "d"() { return "d"},
|
|
||||||
set e(a) { doSomething(a); },
|
|
||||||
set f(a) { doSomething(b); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'var obj={a(){},"b"(){},get c(){return"c"},get"d"(){return"d"},set e(a){doSomething(a)},set f(a){doSomething(b)}};'
|
|
||||||
}
|
|
||||||
|
|
||||||
allow_assignments_to_property_values: {
|
|
||||||
input: {
|
|
||||||
var foo = {123: foo = 123} = {foo: "456"};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = {123: foo = 123} = {foo: "456"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_as_computed_property: {
|
|
||||||
input: {
|
|
||||||
function getLine(header) {
|
|
||||||
return {
|
|
||||||
[header]: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function getLine(header){return{[header]:{}}}"
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
arrow_functions: {
|
|
||||||
input: {
|
|
||||||
(a) => b; // 1 args
|
|
||||||
(a, b) => c; // n args
|
|
||||||
() => b; // 0 args
|
|
||||||
(a) => (b) => c; // func returns func returns func
|
|
||||||
(a) => ((b) => c); // So these parens are dropped
|
|
||||||
() => (b,c) => d; // func returns func returns func
|
|
||||||
a=>{return b;}
|
|
||||||
a => 'lel'; // Dropping the parens
|
|
||||||
}
|
|
||||||
expect_exact: "a=>b;(a,b)=>c;()=>b;a=>b=>c;a=>b=>c;()=>(b,c)=>d;a=>b;a=>\"lel\";"
|
|
||||||
}
|
|
||||||
|
|
||||||
arrow_return: {
|
|
||||||
input: {
|
|
||||||
() => {};
|
|
||||||
() => { return; };
|
|
||||||
a => { return 1; }
|
|
||||||
a => { return -b }
|
|
||||||
a => { return b; var b; }
|
|
||||||
(x, y) => { return x - y; }
|
|
||||||
}
|
|
||||||
expect_exact: "()=>{};()=>{};a=>1;a=>-b;a=>{return b;var b};(x,y)=>x-y;"
|
|
||||||
}
|
|
||||||
|
|
||||||
regression_arrow_functions_and_hoist: {
|
|
||||||
options = {
|
|
||||||
hoist_vars: true,
|
|
||||||
hoist_funs: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
(a) => b;
|
|
||||||
}
|
|
||||||
expect_exact: "a=>b;"
|
|
||||||
}
|
|
||||||
|
|
||||||
regression_assign_arrow_functions: {
|
|
||||||
input: {
|
|
||||||
oninstall = e => false;
|
|
||||||
oninstall = () => false;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
oninstall=e=>false;
|
|
||||||
oninstall=()=>false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_arguments_1: {
|
|
||||||
input: {
|
|
||||||
(function ( a ) { });
|
|
||||||
(function ( [ a ] ) { });
|
|
||||||
(function ( [ a, b ] ) { });
|
|
||||||
(function ( [ [ a ] ] ) { });
|
|
||||||
(function ( [ [ a, b ] ] ) { });
|
|
||||||
(function ( [ a, [ b ] ] ) { });
|
|
||||||
(function ( [ [ b ], a ] ) { });
|
|
||||||
|
|
||||||
(function ( { a } ) { });
|
|
||||||
(function ( { a, b } ) { });
|
|
||||||
|
|
||||||
(function ( [ { a } ] ) { });
|
|
||||||
(function ( [ { a, b } ] ) { });
|
|
||||||
(function ( [ a, { b } ] ) { });
|
|
||||||
(function ( [ { b }, a ] ) { });
|
|
||||||
|
|
||||||
( [ a ] ) => { };
|
|
||||||
( [ a, b ] ) => { };
|
|
||||||
|
|
||||||
( { a } ) => { };
|
|
||||||
( { a, b, c, d, e } ) => { };
|
|
||||||
|
|
||||||
( [ a ] ) => b;
|
|
||||||
( [ a, b ] ) => c;
|
|
||||||
|
|
||||||
( { a } ) => b;
|
|
||||||
( { a, b } ) => c;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
(function(a){});
|
|
||||||
(function([a]){});
|
|
||||||
(function([a,b]){});
|
|
||||||
(function([[a]]){});
|
|
||||||
(function([[a,b]]){});
|
|
||||||
(function([a,[b]]){});
|
|
||||||
(function([[b],a]){});
|
|
||||||
|
|
||||||
(function({a}){});
|
|
||||||
(function({a,b}){});
|
|
||||||
|
|
||||||
(function([{a}]){});
|
|
||||||
(function([{a,b}]){});
|
|
||||||
(function([a,{b}]){});
|
|
||||||
(function([{b},a]){});
|
|
||||||
|
|
||||||
([a])=>{};
|
|
||||||
([a,b])=>{};
|
|
||||||
|
|
||||||
({a})=>{};
|
|
||||||
({a,b,c,d,e})=>{};
|
|
||||||
|
|
||||||
([a])=>b;
|
|
||||||
([a,b])=>c;
|
|
||||||
|
|
||||||
({a})=>b;
|
|
||||||
({a,b})=>c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_arguments_2: {
|
|
||||||
input: {
|
|
||||||
(function([]) {});
|
|
||||||
(function({}) {});
|
|
||||||
(function([,,,,,]) {});
|
|
||||||
(function ([a, {b: c}]) {});
|
|
||||||
(function ([...args]) {});
|
|
||||||
(function ({x,}) {});
|
|
||||||
class a { *method({ [thrower()]: x } = {}) {}};
|
|
||||||
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
(function([]) {});
|
|
||||||
(function({}) {});
|
|
||||||
(function([,,,,,]) {});
|
|
||||||
(function ([a, {b: c}]) {});
|
|
||||||
(function ([...args]) {});
|
|
||||||
(function ({x,}) {});
|
|
||||||
class a { *method({ [thrower()]: x } = {}) {}};
|
|
||||||
(function(a, b, c, d, [{e: [...f]}]){})(1, 2, 3, 4, [{e: [1, 2, 3]}]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destructuring_arguments_3: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function fn3({x: {y: {z: {} = 42}}}) {}
|
|
||||||
const { cover = (function () {}), xCover = (0, function() {}) } = {};
|
|
||||||
let { cover = (function () {}), xCover = (0, function() {}) } = {};
|
|
||||||
var { cover = (function () {}), xCover = (0, function() {}) } = {};
|
|
||||||
}
|
|
||||||
expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{cover=function(){},xCover=(0,function(){})}={};let{cover=function(){},xCover=(0,function(){})}={};var{cover=function(){},xCover=(0,function(){})}={};"
|
|
||||||
}
|
|
||||||
|
|
||||||
default_arguments: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function x(a = 6) { }
|
|
||||||
function x(a = (6 + 5)) { }
|
|
||||||
function x({ foo } = {}, [ bar ] = [ 1 ]) { }
|
|
||||||
}
|
|
||||||
expect_exact: "function x(a=6){}function x(a=6+5){}function x({foo}={},[bar]=[1]){}"
|
|
||||||
}
|
|
||||||
|
|
||||||
default_values_in_destructurings: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function x({a=(4), b}) {}
|
|
||||||
function x([b, c=(12)]) {}
|
|
||||||
var { x = (6), y } = x;
|
|
||||||
var [ x, y = (6) ] = x;
|
|
||||||
}
|
|
||||||
expect_exact: "function x({a=4,b}){}function x([b,c=12]){}var{x=6,y}=x;var[x,y=6]=x;"
|
|
||||||
}
|
|
||||||
|
|
||||||
accept_duplicated_parameters_in_non_strict_without_spread_or_default_assignment: {
|
|
||||||
input: {
|
|
||||||
function a(b, b){}
|
|
||||||
function b({c: test, c: test}){}
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function a(b, b){}
|
|
||||||
function b({c: test, c: test}){}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -148,7 +148,6 @@ mangle_unquoted_properties: {
|
|||||||
properties: false
|
properties: false
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
builtins: true,
|
|
||||||
keep_quoted: true
|
keep_quoted: true
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -239,7 +238,6 @@ mangle_debug_suffix_keep_quoted: {
|
|||||||
properties: false
|
properties: false
|
||||||
}
|
}
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
builtins: true,
|
|
||||||
keep_quoted: true,
|
keep_quoted: true,
|
||||||
debug: "XYZ",
|
debug: "XYZ",
|
||||||
reserved: []
|
reserved: []
|
||||||
|
|||||||
@@ -119,3 +119,62 @@ chained: {
|
|||||||
a.b.c;
|
a.b.c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impure_getter_1: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).a;
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).b;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).a;
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).b;
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
impure_getter_2: {
|
||||||
|
options = {
|
||||||
|
pure_getters: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// will produce incorrect output because getter is not pure
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).a;
|
||||||
|
({
|
||||||
|
get a() {
|
||||||
|
console.log(1);
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}).b;
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,20 +41,20 @@ reduce_vars: {
|
|||||||
var A = 1;
|
var A = 1;
|
||||||
(function() {
|
(function() {
|
||||||
console.log(-3);
|
console.log(-3);
|
||||||
console.log(-4);
|
console.log(A - 5);
|
||||||
})();
|
})();
|
||||||
(function f1() {
|
(function f1() {
|
||||||
var a = 2;
|
var a = 2;
|
||||||
console.log(-3);
|
console.log(a - 5);
|
||||||
eval("console.log(a);");
|
eval("console.log(a);");
|
||||||
})();
|
})();
|
||||||
(function f2(eval) {
|
(function f2(eval) {
|
||||||
var a = 2;
|
var a = 2;
|
||||||
console.log(-3);
|
console.log(a - 5);
|
||||||
eval("console.log(a);");
|
eval("console.log(a);");
|
||||||
})(eval);
|
})(eval);
|
||||||
"yes";
|
"yes";
|
||||||
console.log(2);
|
console.log(A + 1);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -1749,7 +1749,10 @@ redefine_arguments_3: {
|
|||||||
console.log(function() {
|
console.log(function() {
|
||||||
var arguments;
|
var arguments;
|
||||||
return typeof arguments;
|
return typeof arguments;
|
||||||
}(), "number", "undefined");
|
}(), "number", function(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "object number undefined"
|
expect_stdout: "object number undefined"
|
||||||
}
|
}
|
||||||
@@ -2187,10 +2190,11 @@ issue_1814_1: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const a = 42;
|
var a = 42;
|
||||||
!function() {
|
!function() {
|
||||||
var b = a;
|
var b = a;
|
||||||
!function(a) {
|
!function(a) {
|
||||||
@@ -2199,7 +2203,6 @@ issue_1814_1: {
|
|||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const a = 42;
|
|
||||||
!function() {
|
!function() {
|
||||||
!function(a) {
|
!function(a) {
|
||||||
console.log(a++, 42);
|
console.log(a++, 42);
|
||||||
@@ -2213,10 +2216,11 @@ issue_1814_2: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
const a = "32";
|
var a = "32";
|
||||||
!function() {
|
!function() {
|
||||||
var b = a + 1;
|
var b = a + 1;
|
||||||
!function(a) {
|
!function(a) {
|
||||||
@@ -2225,7 +2229,6 @@ issue_1814_2: {
|
|||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
const a = "32";
|
|
||||||
!function() {
|
!function() {
|
||||||
!function(a) {
|
!function(a) {
|
||||||
console.log(a++, "321");
|
console.log(a++, "321");
|
||||||
@@ -2461,3 +2464,76 @@ issue_1865: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1922_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
arguments[0] = 2;
|
||||||
|
return a;
|
||||||
|
}(1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
arguments[0] = 2;
|
||||||
|
return a;
|
||||||
|
}(1));
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1922_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a;
|
||||||
|
eval("a = 1");
|
||||||
|
return a;
|
||||||
|
}(1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a;
|
||||||
|
eval("a = 1");
|
||||||
|
return a;
|
||||||
|
}(1));
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
a = 2;
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}.b, a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
console.log({
|
||||||
|
get a() {
|
||||||
|
a = 2;
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
b: 1
|
||||||
|
}.b, a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,3 +8,12 @@ octal_escape_sequence: {
|
|||||||
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
|
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1929: {
|
||||||
|
input: {
|
||||||
|
function f(s) {
|
||||||
|
return s.split(/[\\/]/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
super_can_be_parsed: {
|
|
||||||
input: {
|
|
||||||
super(1,2);
|
|
||||||
super.meth();
|
|
||||||
}
|
|
||||||
expect_exact: "super(1,2);super.meth();"
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,402 +0,0 @@
|
|||||||
template_strings: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
``;
|
|
||||||
`xx\`x`;
|
|
||||||
`${ foo + 2 }`;
|
|
||||||
` foo ${ bar + `baz ${ qux }` }`;
|
|
||||||
}
|
|
||||||
expect_exact: "``;`xx\\`x`;`${foo+2}`;` foo ${bar+`baz ${qux}`}`;";
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_prefixes: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
String.raw`foo`;
|
|
||||||
foo `bar`;
|
|
||||||
}
|
|
||||||
expect_exact: "String.raw`foo`;foo`bar`;";
|
|
||||||
}
|
|
||||||
|
|
||||||
template_strings_ascii_only: {
|
|
||||||
beautify = {
|
|
||||||
ascii_only: true,
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `foo
|
|
||||||
bar
|
|
||||||
ↂωↂ`;
|
|
||||||
var bar = `\``;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=`foo\\n bar\\n \\u2182\\u03c9\\u2182`;var bar=`\\``;"
|
|
||||||
}
|
|
||||||
|
|
||||||
template_strings_without_ascii_only: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `foo
|
|
||||||
bar
|
|
||||||
ↂωↂ`
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=`foo\\n bar\\n ↂωↂ`;"
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_with_constant_expression: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `${4 + 4} equals 4 + 4`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `8 equals 4 + 4`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_with_predefined_constants: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `This is ${undefined}`;
|
|
||||||
var bar = `This is ${NaN}`;
|
|
||||||
var baz = `This is ${null}`;
|
|
||||||
var foofoo = `This is ${Infinity}`;
|
|
||||||
var foobar = "This is ${1/0}";
|
|
||||||
var foobaz = 'This is ${1/0}';
|
|
||||||
var barfoo = "This is ${NaN}";
|
|
||||||
var bazfoo = "This is ${null}";
|
|
||||||
var bazbaz = `This is ${1/0}`;
|
|
||||||
var barbar = `This is ${0/0}`;
|
|
||||||
var barbar = "This is ${0/0}";
|
|
||||||
var barber = 'This is ${0/0}';
|
|
||||||
|
|
||||||
var a = `${4**11}`; // 8 in template vs 7 chars - 4194304
|
|
||||||
var b = `${4**12}`; // 8 in template vs 8 chars - 16777216
|
|
||||||
var c = `${4**14}`; // 8 in template vs 9 chars - 268435456
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `This is undefined`;
|
|
||||||
var bar = `This is NaN`;
|
|
||||||
var baz = `This is null`;
|
|
||||||
var foofoo = `This is ${1/0}`;
|
|
||||||
var foobar = "This is ${1/0}";
|
|
||||||
var foobaz = 'This is ${1/0}';
|
|
||||||
var barfoo = "This is ${NaN}";
|
|
||||||
var bazfoo = "This is ${null}";
|
|
||||||
var bazbaz = `This is ${1/0}`;
|
|
||||||
var barbar = `This is NaN`;
|
|
||||||
var barbar = "This is ${0/0}";
|
|
||||||
var barber = 'This is ${0/0}';
|
|
||||||
|
|
||||||
var a = `4194304`;
|
|
||||||
var b = `16777216`; // Potential for further concatentation
|
|
||||||
var c = `${4**14}`; // Not worth converting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_evaluate_with_many_segments: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
||||||
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
||||||
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
||||||
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello ${guest()}, welcome to ${location()}.`;
|
|
||||||
var bar = `1234567890`;
|
|
||||||
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
||||||
var buzz = `1${foobar()}2${foobar()}3${foobar()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_with_many_segments: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
||||||
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
||||||
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
||||||
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
||||||
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
||||||
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
||||||
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template_string_to_normal_string: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 0
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `This is ${undefined}`;
|
|
||||||
var bar = "Decimals " + `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `This is undefined`;
|
|
||||||
var bar = "Decimals 1234567890";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template_concattenating_string: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 3 // Yes, keep quotes
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = "Have a nice " + `day. ${`day. ` + `day.`}`;
|
|
||||||
var bar = "Have a nice " + `${day()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = "Have a nice day. day. day.";
|
|
||||||
var bar = "Have a nice " + `${day()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluate_nested_templates: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
beautify = {
|
|
||||||
quote_style: 0
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var baz = `${`${`${`foo`}`}`}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var baz = `foo`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enforce_double_quotes: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 1
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${'world'}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${"world"}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enforce_single_quotes: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 2
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${"world"}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${'world'}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enforce_double_quotes_and_evaluate: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 1
|
|
||||||
}
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${'world'}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello world`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enforce_single_quotes_and_evaluate: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 2
|
|
||||||
}
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello ${"world"}`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = `Hello world`;
|
|
||||||
var bar = `Hello world`;
|
|
||||||
var baz = `Hello ${world()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
respect_inline_script: {
|
|
||||||
beautify = {
|
|
||||||
inline_script: true,
|
|
||||||
quote_style: 3
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = `</script>${content}`;
|
|
||||||
var bar = `<!--`;
|
|
||||||
var baz = `-->`;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=`<\\/script>${content}`;var bar=`\\x3c!--`;var baz=`--\\x3e`;";
|
|
||||||
}
|
|
||||||
|
|
||||||
do_not_optimize_tagged_template_1: {
|
|
||||||
beautify = {
|
|
||||||
quote_style: 0
|
|
||||||
}
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = tag`Shall not be optimized. ${"But " + "this " + "is " + "fine."}`;
|
|
||||||
var bar = tag`Don't even mind changing my quotes!`;
|
|
||||||
}
|
|
||||||
expect_exact:
|
|
||||||
'var foo=tag`Shall not be optimized. ${"But this is fine."}`;var bar=tag`Don\'t even mind changing my quotes!`;';
|
|
||||||
}
|
|
||||||
|
|
||||||
do_not_optimize_tagged_template_2: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = tag`test` + " something out";
|
|
||||||
}
|
|
||||||
expect_exact: 'var foo=tag`test`+" something out";';
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_raw_content_in_tagged_template: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var foo = tag`\u0020\u{20}\u{00020}\x20\40\040 `;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=tag`\\u0020\\u{20}\\u{00020}\\x20\\40\\040 `;";
|
|
||||||
}
|
|
||||||
|
|
||||||
allow_chained_templates: {
|
|
||||||
input: {
|
|
||||||
var foo = tag`a``b``c``d`;
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var foo = tag`a``b``c``d`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
check_escaped_chars: {
|
|
||||||
input: {
|
|
||||||
var foo = `\u0020\u{20}\u{00020}\x20\40\040 `;
|
|
||||||
}
|
|
||||||
expect_exact: "var foo=` `;";
|
|
||||||
}
|
|
||||||
|
|
||||||
escape_dollar_curly: {
|
|
||||||
options = {
|
|
||||||
evaluate: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
console.log(`\$\{ beep \}`)
|
|
||||||
console.log(`${1-0}\${2-0}$\{3-0}${4-0}`)
|
|
||||||
console.log(`$${""}{not an expression}`)
|
|
||||||
}
|
|
||||||
expect_exact: "console.log(`\\${ beep }`);console.log(`1\\${2-0}\\${3-0}4`);console.log(`\\${not an expression}`);"
|
|
||||||
}
|
|
||||||
|
|
||||||
template_starting_with_newline: {
|
|
||||||
options = {
|
|
||||||
dead_code: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function foo(e) {
|
|
||||||
return `
|
|
||||||
this is a template string!`;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect_exact: "function foo(e){return`\\nthis is a template string!`}"
|
|
||||||
}
|
|
||||||
|
|
||||||
template_with_newline: {
|
|
||||||
options = {
|
|
||||||
dead_code: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function foo(e) {
|
|
||||||
return `yep,
|
|
||||||
this is a template string!`;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect_exact: "function foo(e){return`yep,\\nthis is a template string!`}"
|
|
||||||
}
|
|
||||||
|
|
||||||
template_ending_with_newline: {
|
|
||||||
options = {
|
|
||||||
dead_code: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function foo(e) {
|
|
||||||
return `this is a template string!
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect_exact: "function foo(e){return`this is a template string!\\n`}"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1856: {
|
|
||||||
beautify = {
|
|
||||||
ascii_only: false,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
|
|
||||||
}
|
|
||||||
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_1856_ascii_only: {
|
|
||||||
beautify = {
|
|
||||||
ascii_only: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
console.log(`\\n\\r\\u2028\\u2029\n\r\u2028\u2029`);
|
|
||||||
}
|
|
||||||
expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
catch_destructuring_with_sequence: {
|
|
||||||
beautify = {
|
|
||||||
ecma: 6
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
try {
|
|
||||||
throw {};
|
|
||||||
} catch ({xCover = (0, function() {})} ) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "try{throw{}}catch({xCover=(0,function(){})}){}"
|
|
||||||
}
|
|
||||||
@@ -15,106 +15,3 @@ unicode_parse_variables: {
|
|||||||
var l০ = 3;
|
var l০ = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unicode_escaped_identifier: {
|
|
||||||
beautify = {ecma: 6}
|
|
||||||
input: {
|
|
||||||
var \u{61} = "foo";
|
|
||||||
var \u{10000} = "bar";
|
|
||||||
}
|
|
||||||
expect_exact: 'var a="foo";var \u{10000}="bar";';
|
|
||||||
}
|
|
||||||
|
|
||||||
unicode_identifier_ascii_only: {
|
|
||||||
beautify = {ascii_only: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var \u{0061} = "hi";
|
|
||||||
var bar = "h\u{0065}llo";
|
|
||||||
var \u{10000} = "testing \u{101111}";
|
|
||||||
}
|
|
||||||
expect_exact: 'var a="hi";var bar="hello";var \\u{10000}="testing \\u{101111}";'
|
|
||||||
}
|
|
||||||
|
|
||||||
unicode_string_literals: {
|
|
||||||
beautify = {ascii_only: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var a = "6 length unicode character: \u{101111}";
|
|
||||||
}
|
|
||||||
expect_exact: 'var a="6 length unicode character: \\u{101111}";'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't escape identifiers below es6 (or in this case double escaped in expect_exact)
|
|
||||||
unicode_output_es5_surrogates: {
|
|
||||||
beautify = {ascii_only: true, ecma: 5}
|
|
||||||
input: {
|
|
||||||
var \u{10000} = "6 length unicode character: \u{10FFFF}";
|
|
||||||
}
|
|
||||||
expect_exact: 'var \u{10000}="6 length unicode character: \\udbff\\udfff";'
|
|
||||||
}
|
|
||||||
|
|
||||||
check_escape_style: {
|
|
||||||
beautify = {ascii_only: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var a = "\x01";
|
|
||||||
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
|
|
||||||
var \u0100 = "\u0100";
|
|
||||||
var \u1000 = "\u1000";
|
|
||||||
var \u{10000} = "\u{10000}";
|
|
||||||
var \u{2f800} = "\u{100000}";
|
|
||||||
}
|
|
||||||
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \\u{10000}="\\u{10000}";var \\u{2f800}="\\u{100000}";'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't escape identifiers below es6, no escaped identifiers support and no \u{} syntax
|
|
||||||
check_escape_style_es5: {
|
|
||||||
beautify = {ascii_only: true, ecma: 5}
|
|
||||||
input: {
|
|
||||||
var a = "\x01";
|
|
||||||
var \ua0081 = "\x10"; // \u0081 only in ID_Continue
|
|
||||||
var \u0100 = "\u0100";
|
|
||||||
var \u1000 = "\u1000";
|
|
||||||
var \u{10000} = "\u{10000}"; // Identifier won't be escaped in es 5.1
|
|
||||||
var \u{2f800} = "\u{100000}"; // Same
|
|
||||||
}
|
|
||||||
expect_exact: 'var a="\\x01";var \\ua0081="\\x10";var \\u0100="\\u0100";var \\u1000="\\u1000";var \ud800\udc00="\\ud800\\udc00";var \ud87e\udc00="\\udbc0\\udc00";'
|
|
||||||
}
|
|
||||||
|
|
||||||
ID_continue_with_surrogate_pair: {
|
|
||||||
beautify = {ascii_only: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var \u{2f800}\u{2f800}\u{2f800}\u{2f800} = "\u{100000}\u{100000}\u{100000}\u{100000}\u{100000}";
|
|
||||||
}
|
|
||||||
expect_exact: 'var \\u{2f800}\\u{2f800}\\u{2f800}\\u{2f800}="\\u{100000}\\u{100000}\\u{100000}\\u{100000}\\u{100000}";'
|
|
||||||
}
|
|
||||||
|
|
||||||
escape_non_escaped_identifier: {
|
|
||||||
beautify = {ascii_only: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var µþ = "µþ";
|
|
||||||
}
|
|
||||||
expect_exact: 'var \\u00b5\\u00fe="\\xb5\\xfe";'
|
|
||||||
}
|
|
||||||
|
|
||||||
non_escape_2_non_escape: {
|
|
||||||
beautify = {ascii_only: false, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var µþ = "µþ";
|
|
||||||
}
|
|
||||||
expect_exact: 'var µþ="µþ";'
|
|
||||||
}
|
|
||||||
|
|
||||||
non_escape_2_half_escape1: {
|
|
||||||
beautify = {ascii_only: false, ascii_identifiers: true, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var µþ = "µþ";
|
|
||||||
}
|
|
||||||
expect_exact: 'var \\u00b5\\u00fe="µþ";'
|
|
||||||
}
|
|
||||||
|
|
||||||
non_escape_2_half_escape2: {
|
|
||||||
beautify = {ascii_only: true, ascii_identifiers: false, ecma: 6}
|
|
||||||
input: {
|
|
||||||
var µþ = "µþ";
|
|
||||||
}
|
|
||||||
expect_exact: 'var µþ="\\xb5\\xfe";'
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
generators: {
|
|
||||||
input: {
|
|
||||||
function* fn() {};
|
|
||||||
}
|
|
||||||
expect_exact: "function*fn(){}"
|
|
||||||
}
|
|
||||||
|
|
||||||
generators_yield: {
|
|
||||||
input: {
|
|
||||||
function* fn() {
|
|
||||||
yield remote();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function*fn(){yield remote()}"
|
|
||||||
}
|
|
||||||
|
|
||||||
generators_yield_assign: {
|
|
||||||
input: {
|
|
||||||
function* fn() {
|
|
||||||
var x = {};
|
|
||||||
x.prop = yield 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function*fn(){var x={};x.prop=yield 5}"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator_yield_undefined: {
|
|
||||||
input: {
|
|
||||||
function* fn() {
|
|
||||||
yield;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function*fn(){yield}"
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_optimize_expression: {
|
|
||||||
options = {
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function* f1() { yield; }
|
|
||||||
function* f2() { yield undefined; }
|
|
||||||
function* f3() { yield null; }
|
|
||||||
function* f4() { yield* undefined; }
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
function* f1() { yield }
|
|
||||||
function* f2() { yield; }
|
|
||||||
function* f3() { yield null; }
|
|
||||||
function* f4() { yield* void 0; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_statements: {
|
|
||||||
input: {
|
|
||||||
function* fn() {
|
|
||||||
var a = (yield 1) + (yield 2);
|
|
||||||
var b = (yield 3) === (yield 4);
|
|
||||||
var c = (yield 5) << (yield 6);
|
|
||||||
var d = yield 7;
|
|
||||||
var e = (yield 8) ? yield 9 : yield 10;
|
|
||||||
var f = -(yield 11);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function*fn(){var a=(yield 1)+(yield 2);var b=(yield 3)===(yield 4);var c=(yield 5)<<(yield 6);var d=yield 7;var e=(yield 8)?yield 9:yield 10;var f=-(yield 11)}"
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_as_identifier_in_function_in_generator: {
|
|
||||||
input: {
|
|
||||||
var g = function*() {
|
|
||||||
function h() {
|
|
||||||
yield = 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var g = function*() {
|
|
||||||
function h() {
|
|
||||||
yield = 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_before_punctuators: {
|
|
||||||
input: {
|
|
||||||
iter = (function*() {
|
|
||||||
assignmentResult = [ x = yield ] = value;
|
|
||||||
})();
|
|
||||||
function* g1() { (yield) }
|
|
||||||
function* g2() { [yield] }
|
|
||||||
function* g3() { return {yield} } // Added return to avoid {} drop
|
|
||||||
function* g4() { yield, yield; }
|
|
||||||
function* g5() { (yield) ? yield : yield; }
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
iter = (function*() {
|
|
||||||
assignmentResult = [ x = yield ] = value;
|
|
||||||
})();
|
|
||||||
function* g1() { (yield) }
|
|
||||||
function* g2() { [yield] }
|
|
||||||
function* g3() { return {yield} }
|
|
||||||
function* g4() { yield, yield; }
|
|
||||||
function* g5() { (yield) ? yield : yield; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_as_identifier_outside_strict_mode: {
|
|
||||||
input: {
|
|
||||||
import yield from "bar";
|
|
||||||
yield = 123;
|
|
||||||
while (true) {
|
|
||||||
yield:
|
|
||||||
for(;;) break yield;
|
|
||||||
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
while (true)
|
|
||||||
yield: for(;;) continue yield;
|
|
||||||
function yield(){}
|
|
||||||
function foo(...yield){}
|
|
||||||
try { new Error("") } catch (yield) {}
|
|
||||||
var yield = "foo";
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
import yield from "bar";
|
|
||||||
yield = 123;
|
|
||||||
while (true) {
|
|
||||||
yield:
|
|
||||||
for(;;) break yield;
|
|
||||||
|
|
||||||
foo();
|
|
||||||
}
|
|
||||||
while (true)
|
|
||||||
yield: for(;;) continue yield;
|
|
||||||
function yield(){}
|
|
||||||
function foo(...yield){}
|
|
||||||
try { new Error("") } catch (yield) {}
|
|
||||||
var yield = "foo";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
empty_generator_as_parameter_with_side_effects: {
|
|
||||||
options = {
|
|
||||||
side_effects: true
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var GeneratorPrototype = Object.getPrototypeOf(
|
|
||||||
Object.getPrototypeOf(function*() {}())
|
|
||||||
);
|
|
||||||
evaluate(GeneratorPrototype);
|
|
||||||
}
|
|
||||||
expect_exact: "var GeneratorPrototype=Object.getPrototypeOf(Object.getPrototypeOf(function*(){}()));evaluate(GeneratorPrototype);"
|
|
||||||
}
|
|
||||||
|
|
||||||
empty_generator_as_parameter_without_side_effects: {
|
|
||||||
options = {
|
|
||||||
side_effects: false
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
var GeneratorPrototype = Object.getPrototypeOf(
|
|
||||||
Object.getPrototypeOf(function*() {}())
|
|
||||||
);
|
|
||||||
evaluate(GeneratorPrototype);
|
|
||||||
}
|
|
||||||
expect_exact: "var GeneratorPrototype=Object.getPrototypeOf(Object.getPrototypeOf(function*(){}()));evaluate(GeneratorPrototype);"
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_dot: {
|
|
||||||
options = {
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function* foo(){
|
|
||||||
yield x.foo;
|
|
||||||
(yield x).foo;
|
|
||||||
yield (yield obj.foo()).bar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: "function*foo(){yield x.foo;(yield x).foo;yield(yield obj.foo()).bar()}"
|
|
||||||
}
|
|
||||||
|
|
||||||
yield_sub: {
|
|
||||||
options = {
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
function* foo(){
|
|
||||||
yield x['foo'];
|
|
||||||
(yield x)['foo'];
|
|
||||||
yield (yield obj.foo())['bar']();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect_exact: 'function*foo(){yield x["foo"];(yield x)["foo"];yield(yield obj.foo())["bar"]()}'
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
function f() {
|
|
||||||
const a;
|
|
||||||
}
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
"use strict";
|
|
||||||
const a;
|
|
||||||
}
|
|
||||||
1
test/input/invalid/else.js
Normal file
1
test/input/invalid/else.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
if (0) else 1;
|
||||||
1
test/input/invalid/return.js
Normal file
1
test/input/invalid/return.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
return 42;
|
||||||
@@ -16,8 +16,8 @@ describe("Accessor tokens", function() {
|
|||||||
assert.equal(node.start.pos, 12);
|
assert.equal(node.start.pos, 12);
|
||||||
assert.equal(node.end.endpos, 46);
|
assert.equal(node.end.endpos, 46);
|
||||||
|
|
||||||
assert(node.key instanceof UglifyJS.AST_SymbolMethod);
|
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
||||||
assert.equal(node.key.start.pos, 12);
|
assert.equal(node.key.start.pos, 16);
|
||||||
assert.equal(node.key.end.endpos, 22);
|
assert.equal(node.key.end.endpos, 22);
|
||||||
|
|
||||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||||
|
|||||||
@@ -27,253 +27,4 @@ describe("arguments", function() {
|
|||||||
assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
|
assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
|
||||||
assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false);
|
assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
it("Should parse a function containing default assignment correctly", function() {
|
|
||||||
var ast = UglifyJS.parse("function foo(a = 123) {}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo(a = a) {}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].right instanceof UglifyJS.AST_SymbolRef);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse a function containing default assignments in destructuring correctly", function() {
|
|
||||||
var ast = UglifyJS.parse("function foo([a = 123]) {}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo({a = 123}) {}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
|
||||||
|
|
||||||
// Property a of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo({a: a = 123}) {}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
|
||||||
|
|
||||||
// Content destructuring of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
|
|
||||||
// Property a of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.right instanceof UglifyJS.AST_Number);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse a function containing default assignments in complex destructuring correctly", function() {
|
|
||||||
var ast = UglifyJS.parse("function foo([a, [b = 123]]){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].is_array, true);
|
|
||||||
|
|
||||||
// Check content of second destructuring element (which is the nested destructuring pattern)
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0] instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo([a, {b: c = 123}]){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].is_array, false);
|
|
||||||
|
|
||||||
// Check content of second destructuring element (which is the nested destructuring pattern)
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].key, "b");
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
|
|
||||||
// Property b of second argument
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].argnames[0].names[1].names[0].value.right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo({a, b: {b = 123}}){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[1].key, "b");
|
|
||||||
assert(ast.body[0].argnames[0].names[1].value instanceof UglifyJS.AST_Destructuring);
|
|
||||||
|
|
||||||
// Check content of nested destructuring in first parameter
|
|
||||||
var content = ast.body[0].argnames[0].names[1].value
|
|
||||||
assert.strictEqual(content.is_array, false);
|
|
||||||
assert.strictEqual(content.names.length, 1);
|
|
||||||
assert(content.names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(content.names[0].key, "b");
|
|
||||||
assert(content.names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(content.names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(content.names[0].value.operator, "=");
|
|
||||||
assert(content.names[0].value.right instanceof UglifyJS.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo({a: {b = 123}}){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_Destructuring);
|
|
||||||
|
|
||||||
// Check content of nested destructuring
|
|
||||||
content = ast.body[0].argnames[0].names[0].value
|
|
||||||
assert.strictEqual(content.is_array, false);
|
|
||||||
assert.strictEqual(content.names.length, 1);
|
|
||||||
assert(content.names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(content.names[0].key, "b");
|
|
||||||
assert(content.names[0].value instanceof UglifyJS.AST_DefaultAssign);
|
|
||||||
assert(content.names[0].value.left instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(content.names[0].value.operator, "=");
|
|
||||||
assert(content.names[0].value.right instanceof UglifyJS.AST_Number);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse spread correctly", function() {
|
|
||||||
var ast = UglifyJS.parse("function foo(a, b, ...c){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 3);
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[1] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[2] instanceof UglifyJS.AST_Expansion);
|
|
||||||
assert(ast.body[0].argnames[2].expression instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo([a, b, ...c]){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
|
||||||
|
|
||||||
// Check content first parameter
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[2] instanceof UglifyJS.AST_Expansion);
|
|
||||||
assert(ast.body[0].argnames[0].names[2].expression instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo([a, b, [c, ...d]]){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, true);
|
|
||||||
|
|
||||||
// Check content outer destructuring array
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[1] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[2] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[2].is_array, true);
|
|
||||||
|
|
||||||
// Check content nested destructuring array
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[2].names.length, 2);
|
|
||||||
assert(ast.body[0].argnames[0].names[2].names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[2].names[1] instanceof UglifyJS.AST_Expansion);
|
|
||||||
assert(ast.body[0].argnames[0].names[2].names[1].expression instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = UglifyJS.parse("function foo({a: [b, ...c]}){}");
|
|
||||||
assert(ast.body[0] instanceof UglifyJS.AST_Defun);
|
|
||||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].argnames[0] instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].is_array, false);
|
|
||||||
|
|
||||||
// Check outer destructuring object
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].argnames[0].names[0] instanceof UglifyJS.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value instanceof UglifyJS.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].value.is_array, true);
|
|
||||||
|
|
||||||
// Check content nested destructuring array
|
|
||||||
assert.strictEqual(ast.body[0].argnames[0].names[0].value.names.length, 2);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.names[0] instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.names[1] instanceof UglifyJS.AST_Expansion);
|
|
||||||
assert(ast.body[0].argnames[0].names[0].value.names[1].expression instanceof UglifyJS.AST_SymbolFunarg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,402 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Arrow functions", function() {
|
|
||||||
it("Should not accept spread tokens on non-last parameters or without arguments parentheses", function() {
|
|
||||||
var tests = [
|
|
||||||
"var a = ...a => {return a.join()}",
|
|
||||||
"var b = (a, ...b, c) => { return a + b.join() + c}",
|
|
||||||
"var c = (...a, b) => a.join()"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected token: expand (...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should not accept holes in object binding patterns, while still allowing a trailing elision", function() {
|
|
||||||
var tests = [
|
|
||||||
"f = ({, , ...x} = [1, 2]) => {};"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected token: punc (,)";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should not accept newlines before arrow token", function() {
|
|
||||||
var tests = [
|
|
||||||
"f = foo\n=> 'foo';",
|
|
||||||
"f = (foo, bar)\n=> 'foo';",
|
|
||||||
"f = ()\n=> 'foo';",
|
|
||||||
"foo((bar)\n=>'baz';);"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected newline before arrow (=>)";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should not accept arrow functions in the middle or end of an expression", function() {
|
|
||||||
var tests = [
|
|
||||||
"typeof x => 0",
|
|
||||||
"0 + x => 0"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected token: arrow (=>)";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse a function containing default assignment correctly", function() {
|
|
||||||
var ast = uglify.parse("var a = (a = 123) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = (a = a) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].right instanceof uglify.AST_SymbolRef);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse a function containing default assignments in destructuring correctly", function() {
|
|
||||||
var ast = uglify.parse("var a = ([a = 123]) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ({a = 123}) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
|
|
||||||
// First object element in first argument
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ({a: a = 123}) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// First argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
|
||||||
|
|
||||||
// Content destructuring of first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectProperty);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse a function containing default assignments in complex destructuring correctly", function() {
|
|
||||||
var ast = uglify.parse("var a = ([a, [b = 123]]) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].is_array, true);
|
|
||||||
|
|
||||||
// Check content of second destructuring element (which is the nested destructuring pattern)
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ([a, {b: c = 123}]) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].is_array, false);
|
|
||||||
|
|
||||||
// Check content of second destructuring element (which is the nested destructuring pattern)
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].key, "b");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ({a, b: {b = 123}}) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 2);
|
|
||||||
|
|
||||||
// First argument, property 1
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
// First argument, property 2
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[1].key, "b");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1].value instanceof uglify.AST_Destructuring);
|
|
||||||
|
|
||||||
// Check content of nested destructuring
|
|
||||||
var content = ast.body[0].definitions[0].value.argnames[0].names[1].value
|
|
||||||
assert.strictEqual(content.is_array, false);
|
|
||||||
assert.strictEqual(content.names.length, 1);
|
|
||||||
assert(content.names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
|
|
||||||
// Content of first property in nested destructuring
|
|
||||||
assert.strictEqual(content.names[0].key, "b");
|
|
||||||
assert(content.names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(content.names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(content.names[0].value.operator, "=");
|
|
||||||
assert(content.names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ({a: {b = 123}}) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
|
||||||
|
|
||||||
// Check whole destructuring structure of first argument
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_Destructuring);
|
|
||||||
|
|
||||||
// Check content of nested destructuring
|
|
||||||
content = ast.body[0].definitions[0].value.argnames[0].names[0].value
|
|
||||||
assert.strictEqual(content.is_array, false);
|
|
||||||
assert.strictEqual(content.names.length, 1);
|
|
||||||
assert(content.names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
|
|
||||||
// Check first property of nested destructuring
|
|
||||||
assert.strictEqual(content.names[0].key, "b");
|
|
||||||
assert(content.names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(content.names[0].value.left instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert.strictEqual(content.names[0].value.operator, "=");
|
|
||||||
assert(content.names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse spread correctly", function() {
|
|
||||||
var ast = uglify.parse("var a = (a, b, ...c) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 3);
|
|
||||||
|
|
||||||
// Check parameters
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[1] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[2] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[2].expression instanceof uglify.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ([a, b, ...c]) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
|
||||||
|
|
||||||
// Check content first parameter
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2].expression instanceof uglify.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ([a, b, [c, ...d]]) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, true);
|
|
||||||
|
|
||||||
// Check content outer destructuring array
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[1] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[2].is_array, true);
|
|
||||||
|
|
||||||
// Check content nested destructuring array
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[2].names.length, 2);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[1] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[2].names[1].expression instanceof uglify.AST_SymbolFunarg);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("var a = ({a: [b, ...c]}) => {}");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert.strictEqual(ast.body[0].definitions.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0] instanceof uglify.AST_VarDef);
|
|
||||||
assert(ast.body[0].definitions[0].name instanceof uglify.AST_SymbolVar);
|
|
||||||
assert(ast.body[0].definitions[0].value instanceof uglify.AST_Arrow);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames.length, 1);
|
|
||||||
|
|
||||||
// Check first parameter
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].is_array, false);
|
|
||||||
|
|
||||||
// Check outer destructuring object
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names.length, 1);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0] instanceof uglify.AST_ObjectKeyVal);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].key, "a");
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.is_array, true);
|
|
||||||
|
|
||||||
// Check content nested destructuring array
|
|
||||||
assert.strictEqual(ast.body[0].definitions[0].value.argnames[0].names[0].value.names.length, 2);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[0] instanceof uglify.AST_SymbolFunarg);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[1] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[0].definitions[0].value.argnames[0].names[0].value.names[1].expression instanceof uglify.AST_SymbolFunarg);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should handle arrow function with bind", function() {
|
|
||||||
function minify(code) {
|
|
||||||
return uglify.minify(code, {
|
|
||||||
mangle: false
|
|
||||||
}).code;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.strictEqual(
|
|
||||||
minify(minify("test(((index) => { console.log(this, index); }).bind(this, 1));")),
|
|
||||||
"test((index=>{console.log(this,index)}).bind(this,1));"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
minify(minify('test(((index) => { console.log(this, index); })["bind"](this, 1));')),
|
|
||||||
"test((index=>{console.log(this,index)}).bind(this,1));"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
var UglifyJS = require("../../");
|
|
||||||
var assert = require("assert");
|
|
||||||
|
|
||||||
describe("builtins", function() {
|
|
||||||
it ("Should not mangle builtins", function() {
|
|
||||||
var test = "function foo(something){\n" +
|
|
||||||
" return [Object,Array,Function,Number,String,Boolean,Error,Math,Date,RegExp,Symbol,Map,Promise,Proxy,Reflect,Set,WeakMap,WeakSet,Float32Array,something];\n" +
|
|
||||||
"};";
|
|
||||||
|
|
||||||
var result = UglifyJS.minify(test, {parse: {bare_returns: true}}).code;
|
|
||||||
|
|
||||||
assert.strictEqual(result.indexOf("something"), -1);
|
|
||||||
|
|
||||||
assert.notEqual(result.indexOf("Object"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Array"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Function"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Number"), -1);
|
|
||||||
assert.notEqual(result.indexOf("String"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Boolean"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Error"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Math"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Date"), -1);
|
|
||||||
assert.notEqual(result.indexOf("RegExp"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Symbol"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Promise"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Proxy"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Reflect"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Set"), -1);
|
|
||||||
assert.notEqual(result.indexOf("WeakMap"), -1);
|
|
||||||
assert.notEqual(result.indexOf("WeakSet"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Map"), -1);
|
|
||||||
assert.notEqual(result.indexOf("Float32Array"), -1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Class", function() {
|
|
||||||
it("Should not accept spread on non-last parameters in methods", function() {
|
|
||||||
var tests = [
|
|
||||||
"class foo { bar(...a, b) { return a.join(b) } }",
|
|
||||||
"class foo { bar(a, b, ...c, d) { return c.join(a + b) + d } }",
|
|
||||||
"class foo { *bar(...a, b) { return a.join(b) } }",
|
|
||||||
"class foo { *bar(a, b, ...c, d) { return c.join(a + b) + d } }"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
/^Unexpected token: /.test(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should return the correct token for class methods", function() {
|
|
||||||
var tests = [
|
|
||||||
{
|
|
||||||
code: "class foo{static test(){}}",
|
|
||||||
token_value_start: "static",
|
|
||||||
token_value_end: "}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: "class bar{*procedural(){}}",
|
|
||||||
token_value_start: "*",
|
|
||||||
token_value_end: "}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: "class foobar{aMethod(){}}",
|
|
||||||
token_value_start: "aMethod",
|
|
||||||
token_value_end: "}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: "class foobaz{get something(){}}",
|
|
||||||
token_value_start: "get",
|
|
||||||
token_value_end: "}"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
var ast = uglify.parse(tests[i].code);
|
|
||||||
assert.strictEqual(ast.body[0].properties[0].start.value, tests[i].token_value_start);
|
|
||||||
assert.strictEqual(ast.body[0].properties[0].end.value, tests[i].token_value_end);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -19,7 +19,9 @@ describe("bin/uglifyjs", function () {
|
|||||||
eval(stdout);
|
eval(stdout);
|
||||||
|
|
||||||
assert.strictEqual(typeof WrappedUglifyJS, 'object');
|
assert.strictEqual(typeof WrappedUglifyJS, 'object');
|
||||||
assert.strictEqual(WrappedUglifyJS.minify("foo([true,,2+3]);").code, "foo([!0,,5]);");
|
var result = WrappedUglifyJS.minify("foo([true,,2+3]);");
|
||||||
|
assert.strictEqual(result.error, undefined);
|
||||||
|
assert.strictEqual(result.code, "foo([!0,,5]);");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -55,15 +57,15 @@ describe("bin/uglifyjs", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should append source map to output when using --source-map url=inline", function (done) {
|
it("Should append source map to output when using --source-map url=inline", function (done) {
|
||||||
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map url=inline";
|
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map url=inline";
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
|
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
|
||||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("should not append source map to output when not using --source-map url=inline", function (done) {
|
it("should not append source map to output when not using --source-map url=inline", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
|
var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
|
||||||
@@ -76,84 +78,84 @@ describe("bin/uglifyjs", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --keep-fnames (mangle only)", function (done) {
|
it("Should work with --keep-fnames (mangle only)", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
|
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
|
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --keep-fnames (mangle & compress)", function (done) {
|
it("Should work with --keep-fnames (mangle & compress)", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
|
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
|
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with keep_fnames under mangler options", function (done) {
|
it("Should work with keep_fnames under mangler options", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
|
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
|
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --define (simple)", function (done) {
|
it("Should work with --define (simple)", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
|
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "console.log(5);\n");
|
assert.strictEqual(stdout, "console.log(5);\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --define (nested)", function (done) {
|
it("Should work with --define (nested)", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
|
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "console.log(3,5);\n");
|
assert.strictEqual(stdout, "console.log(3,5);\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with --define (AST_Node)", function (done) {
|
it("Should work with --define (AST_Node)", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
|
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, "stdout.println(D);\n");
|
assert.strictEqual(stdout, "stdout.println(D);\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with `--beautify`", function (done) {
|
it("Should work with `--beautify`", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
|
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
|
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with `--beautify bracketize`", function (done) {
|
it("Should work with `--beautify bracketize`", function (done) {
|
||||||
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
|
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, read("test/input/issue-1482/bracketize.js"));
|
assert.strictEqual(stdout, read("test/input/issue-1482/bracketize.js"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should process inline source map", function(done) {
|
it("Should process inline source map", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline";
|
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline";
|
||||||
@@ -260,229 +262,244 @@ describe("bin/uglifyjs", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (5--)", function(done) {
|
it("Should throw syntax error (5--)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
|
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/assign_1.js:1,18",
|
"Parse error at test/input/invalid/assign_1.js:1,18",
|
||||||
"console.log(1 || 5--);",
|
"console.log(1 || 5--);",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Invalid use of -- operator"
|
"ERROR: Invalid use of -- operator"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
|
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/assign_2.js:1,32",
|
"Parse error at test/input/invalid/assign_2.js:1,32",
|
||||||
"console.log(2 || (Math.random() /= 2));",
|
"console.log(2 || (Math.random() /= 2));",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Invalid assignment"
|
"ERROR: Invalid assignment"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (++this)", function(done) {
|
it("Should throw syntax error (++this)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
|
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/assign_3.js:1,17",
|
"Parse error at test/input/invalid/assign_3.js:1,17",
|
||||||
"console.log(3 || ++this);",
|
"console.log(3 || ++this);",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Invalid use of ++ operator"
|
"ERROR: Invalid use of ++ operator"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (++null)", function(done) {
|
it("Should throw syntax error (++null)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
|
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/assign_4.js:1,0",
|
"Parse error at test/input/invalid/assign_4.js:1,0",
|
||||||
"++null",
|
"++null",
|
||||||
"^",
|
"^",
|
||||||
"ERROR: Invalid use of ++ operator"
|
"ERROR: Invalid use of ++ operator"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (a.=)", function(done) {
|
it("Should throw syntax error (a.=)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
|
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/dot_1.js:1,2",
|
"Parse error at test/input/invalid/dot_1.js:1,2",
|
||||||
"a.=",
|
"a.=",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected token: operator (=)"
|
"ERROR: Unexpected token: operator (=)"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (%.a)", function(done) {
|
it("Should throw syntax error (%.a)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
|
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/dot_2.js:1,0",
|
"Parse error at test/input/invalid/dot_2.js:1,0",
|
||||||
"%.a;",
|
"%.a;",
|
||||||
"^",
|
"^",
|
||||||
"ERROR: Unexpected token: operator (%)"
|
"ERROR: Unexpected token: operator (%)"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (a./();)", function(done) {
|
it("Should throw syntax error (a./();)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
|
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/dot_3.js:1,2",
|
"Parse error at test/input/invalid/dot_3.js:1,2",
|
||||||
"a./();",
|
"a./();",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected token: operator (/)"
|
"ERROR: Unexpected token: operator (/)"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error ({%: 1})", function(done) {
|
it("Should throw syntax error ({%: 1})", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/object.js';
|
var command = uglifyjscmd + ' test/input/invalid/object.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/object.js:1,13",
|
"Parse error at test/input/invalid/object.js:1,13",
|
||||||
"console.log({%: 1});",
|
"console.log({%: 1});",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected token: operator (%)"
|
"ERROR: Unexpected token: operator (%)"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
it("Should throw syntax error (const a)", function(done) {
|
|
||||||
var command = uglifyjscmd + ' test/input/invalid/const.js';
|
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
|
||||||
assert.ok(err);
|
|
||||||
assert.strictEqual(stdout, "");
|
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
|
||||||
"Parse error at test/input/invalid/const.js:7,11",
|
|
||||||
" const a;",
|
|
||||||
" ^",
|
|
||||||
"ERROR: Missing initializer in const declaration"
|
|
||||||
].join("\n"));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (delete x)", function(done) {
|
it("Should throw syntax error (delete x)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/delete.js';
|
var command = uglifyjscmd + ' test/input/invalid/delete.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/delete.js:13,11",
|
"Parse error at test/input/invalid/delete.js:13,11",
|
||||||
" delete x;",
|
" delete x;",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Calling delete on expression not allowed in strict mode"
|
"ERROR: Calling delete on expression not allowed in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (function g(arguments))", function(done) {
|
it("Should throw syntax error (function g(arguments))", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
|
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/function_1.js:4,11",
|
"Parse error at test/input/invalid/function_1.js:4,11",
|
||||||
"function g(arguments) {",
|
"function g(arguments) {",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected arguments in strict mode"
|
"ERROR: Unexpected arguments in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (function eval())", function(done) {
|
it("Should throw syntax error (function eval())", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
|
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/function_2.js:4,9",
|
"Parse error at test/input/invalid/function_2.js:4,9",
|
||||||
"function eval() {",
|
"function eval() {",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected eval in strict mode"
|
"ERROR: Unexpected eval in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (iife arguments())", function(done) {
|
it("Should throw syntax error (iife arguments())", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
|
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/function_3.js:4,10",
|
"Parse error at test/input/invalid/function_3.js:4,10",
|
||||||
"!function arguments() {",
|
"!function arguments() {",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected arguments in strict mode"
|
"ERROR: Unexpected arguments in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (catch(eval))", function(done) {
|
it("Should throw syntax error (catch(eval))", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/try.js';
|
var command = uglifyjscmd + ' test/input/invalid/try.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/try.js:7,18",
|
"Parse error at test/input/invalid/try.js:7,18",
|
||||||
" try {} catch (eval) {}",
|
" try {} catch (eval) {}",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected eval identifier as parameter inside strict mode"
|
"ERROR: Unexpected eval in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should throw syntax error (var eval)", function(done) {
|
it("Should throw syntax error (var eval)", function(done) {
|
||||||
var command = uglifyjscmd + ' test/input/invalid/var.js';
|
var command = uglifyjscmd + ' test/input/invalid/var.js';
|
||||||
|
|
||||||
exec(command, function (err, stdout, stderr) {
|
exec(command, function (err, stdout, stderr) {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
assert.strictEqual(stdout, "");
|
assert.strictEqual(stdout, "");
|
||||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
"Parse error at test/input/invalid/var.js:7,8",
|
"Parse error at test/input/invalid/var.js:7,8",
|
||||||
" var eval;",
|
" var eval;",
|
||||||
" ^",
|
" ^",
|
||||||
"ERROR: Unexpected eval in strict mode"
|
"ERROR: Unexpected eval in strict mode"
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (else)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/else.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/else.js:1,7",
|
||||||
|
"if (0) else 1;",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected token: keyword (else)"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (return)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/return.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/return.js:1,0",
|
||||||
|
"return 42;",
|
||||||
|
"^",
|
||||||
|
"ERROR: 'return' outside of function"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it("Should handle literal string as source map input", function(done) {
|
it("Should handle literal string as source map input", function(done) {
|
||||||
var command = [
|
var command = [
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ describe("Comment", function() {
|
|||||||
"/*Some comment 2\r\n\r\n\r\n*/\r\n>\n\n\n\n\n\n",
|
"/*Some comment 2\r\n\r\n\r\n*/\r\n>\n\n\n\n\n\n",
|
||||||
"/*Some comment 3\r\r\r*/\r>\n\n\n\n\n\n",
|
"/*Some comment 3\r\r\r*/\r>\n\n\n\n\n\n",
|
||||||
"/*Some comment 4\u2028\u2028\u2028*/\u2028>\n\n\n\n\n\n",
|
"/*Some comment 4\u2028\u2028\u2028*/\u2028>\n\n\n\n\n\n",
|
||||||
"/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n",
|
"/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n"
|
||||||
"/*Some comment 6\udbff\udfff\udbff\udfff\n\n\n*/\n>\n\n\n\n\n"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
var fail = function(e) {
|
var fail = function(e) {
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Destructuring", function() {
|
|
||||||
it("Should generate similar trees for destructuring in left hand side expressions, definitions, functions and arrow functions", function() {
|
|
||||||
var patterns = [
|
|
||||||
"[]",
|
|
||||||
"{}",
|
|
||||||
|
|
||||||
"[a, b, c]",
|
|
||||||
"{a: b, c: d}",
|
|
||||||
"{a}",
|
|
||||||
"{a, b}",
|
|
||||||
|
|
||||||
"{a: {}}",
|
|
||||||
"{a: []}",
|
|
||||||
"[{}]",
|
|
||||||
"[[]]",
|
|
||||||
"{a: {b}}",
|
|
||||||
|
|
||||||
// Can't do `a = 123` with lhs expression, so only test in destructuring
|
|
||||||
"[foo = bar]",
|
|
||||||
"{a = 123}",
|
|
||||||
"[{foo: abc = 123}]",
|
|
||||||
"{foo: [abc = 123]}",
|
|
||||||
|
|
||||||
"[...foo]",
|
|
||||||
"[...{}]",
|
|
||||||
"[...[]]"
|
|
||||||
|
|
||||||
// Can't do `...` because that is an invalid lhs expression, spread in array destructuring should be fine though
|
|
||||||
];
|
|
||||||
|
|
||||||
var types = [
|
|
||||||
{
|
|
||||||
name: "lhs",
|
|
||||||
symbolType: uglify.AST_SymbolRef,
|
|
||||||
tree: function (ast) {
|
|
||||||
return ast.body[0].body.left;
|
|
||||||
},
|
|
||||||
generate: function (code) {
|
|
||||||
return "(" + code + " = a)";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "var",
|
|
||||||
symbolType: uglify.AST_SymbolVar,
|
|
||||||
tree: function (ast) {
|
|
||||||
return ast.body[0].definitions[0].name;
|
|
||||||
},
|
|
||||||
generate: function (code) {
|
|
||||||
return "var " + code + " = a";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "function",
|
|
||||||
symbolType: uglify.AST_SymbolFunarg,
|
|
||||||
tree: function (ast) {
|
|
||||||
return ast.body[0].argnames[0];
|
|
||||||
},
|
|
||||||
generate: function (code) {
|
|
||||||
return "function a(" + code + ") {}";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "arrow",
|
|
||||||
symbolType: uglify.AST_SymbolFunarg,
|
|
||||||
tree: function (ast) {
|
|
||||||
return ast.body[0].definitions[0].value.argnames[0];
|
|
||||||
},
|
|
||||||
generate: function (code) {
|
|
||||||
return "var a = (" + code + ") => {}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var walker = function(type, ref, code, result) {
|
|
||||||
var w = new uglify.TreeWalker(function(node) {
|
|
||||||
if (w.parent() instanceof uglify.AST_DefaultAssign &&
|
|
||||||
w.parent().right === node
|
|
||||||
) {
|
|
||||||
return true; // Don't check the content of the default assignment
|
|
||||||
|
|
||||||
} else if (node instanceof uglify.AST_Symbol) {
|
|
||||||
assert(node instanceof type.symbolType,
|
|
||||||
node.TYPE + " while " + type.symbolType.TYPE + " expected at pos " +
|
|
||||||
node.start.pos + " in `" + code + "` (" + ref + ")"
|
|
||||||
);
|
|
||||||
|
|
||||||
result.push([
|
|
||||||
new uglify.AST_Symbol({
|
|
||||||
start: node.start,
|
|
||||||
name: node.name,
|
|
||||||
end: node.end
|
|
||||||
}),
|
|
||||||
w.parent()
|
|
||||||
]);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.push([node, w.parent()]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return w;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getNodeType = function(node) {
|
|
||||||
return node[0].TYPE + (node[1] ? " " + node[1].TYPE : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < patterns.length; i++) {
|
|
||||||
var results = [];
|
|
||||||
|
|
||||||
for (var j = 0; j < types.length; j++) {
|
|
||||||
var code = types[j].generate(patterns[i])
|
|
||||||
var ast = types[j].tree(
|
|
||||||
uglify.parse(code)
|
|
||||||
);
|
|
||||||
results.push([]);
|
|
||||||
ast.walk(walker(
|
|
||||||
types[j],
|
|
||||||
"`" + patterns[i] + "` on " + types[j].name,
|
|
||||||
code,
|
|
||||||
results[j]
|
|
||||||
));
|
|
||||||
|
|
||||||
if (j > 0) {
|
|
||||||
assert.deepEqual(
|
|
||||||
results[0].map(getNodeType),
|
|
||||||
results[j].map(getNodeType),
|
|
||||||
"AST disagree on " + patterns[i] + " with " + types[j].name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -62,10 +62,10 @@ describe("Directives", function() {
|
|||||||
it("Should know which strings are directive and which ones are not", function() {
|
it("Should know which strings are directive and which ones are not", function() {
|
||||||
var test_directive = function(tokenizer, test) {
|
var test_directive = function(tokenizer, test) {
|
||||||
test.directives.map(function(directive) {
|
test.directives.map(function(directive) {
|
||||||
assert.strictEqual(tokenizer.has_directive(directive), true, "Didn't found directive `" + directive + "` at the end of `" + test.input + '`');
|
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input);
|
||||||
});
|
});
|
||||||
test.non_directives.map(function(fake_directive) {
|
test.non_directives.map(function(fake_directive) {
|
||||||
assert.strictEqual(tokenizer.has_directive(fake_directive), false, "Unexpectedly found directive `" + fake_directive + "` at the end of `" + test.input + '`');
|
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,16 +156,6 @@ describe("Directives", function() {
|
|||||||
input: '"use strict";try{"use asm";',
|
input: '"use strict";try{"use asm";',
|
||||||
directives: ["use strict"],
|
directives: ["use strict"],
|
||||||
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'class foo {',
|
|
||||||
directives: ["use strict"],
|
|
||||||
non_directives: ["use\nstrict", "use asm"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'class foo {}',
|
|
||||||
directives: [],
|
|
||||||
non_directives: ["use strict", "use asm", "use\nstrict"]
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -361,61 +351,31 @@ describe("Directives", function() {
|
|||||||
var tests = [
|
var tests = [
|
||||||
[
|
[
|
||||||
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
|
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
|
||||||
'"use strict";"use foo";doSomething("foo");'
|
'"use strict";"use foo";doSomething("foo");',
|
||||||
|
'function f(){ "use strict" }',
|
||||||
|
'function f(){ "use asm" }',
|
||||||
|
'function f(){ "use nondirective" }',
|
||||||
|
'function f(){ ;"use strict" }',
|
||||||
|
'function f(){ "use \n"; }',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
||||||
'"use asm";"use\\x20strict";1+1;',
|
'"use asm";"use\\x20strict";1+1;',
|
||||||
'"use asm";;"use strict";1+1;' // Yet, the parser noticed that "use strict" wasn't a directive
|
'"use asm";;"use strict";1+1;', // Yet, the parser noticed that "use strict" wasn't a directive
|
||||||
|
'function f(){"use strict"}',
|
||||||
|
'function f(){"use asm"}',
|
||||||
|
'function f(){"use nondirective"}',
|
||||||
|
'function f(){}',
|
||||||
|
'function f(){}',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
uglify.minify(tests[i][0], {compress: {collapse_vars: true, side_effects: true}}).code,
|
uglify.minify(tests[i][0]).code,
|
||||||
tests[i][1],
|
tests[i][1],
|
||||||
tests[i][0]
|
tests[i][0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it("Should be detect implicit usages of strict mode from tree walker", function() {
|
|
||||||
var tests = [
|
|
||||||
{
|
|
||||||
input: 'class foo {bar(){_check_}}',
|
|
||||||
directives: ["use strict"],
|
|
||||||
non_directives: ["use bar"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: 'class foo {bar(){}}_check_',
|
|
||||||
directives: [],
|
|
||||||
non_directives: ["use strict", "use bar"]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
var checked;
|
|
||||||
var checkWalker = new uglify.TreeWalker(function(node, descend) {
|
|
||||||
if (node instanceof uglify.AST_Symbol && node.name === "_check_") {
|
|
||||||
checked = true;
|
|
||||||
for (var j = 0; j < tests[i].directives.length; j++) {
|
|
||||||
assert.ok(checkWalker.has_directive(tests[i].directives[j]),
|
|
||||||
"Did not found directive '" + tests[i].directives[j] + "' in test " + tests[i].input)
|
|
||||||
}
|
|
||||||
for (var k = 0; k < tests[i].non_directives.length; k++) {
|
|
||||||
assert.equal(checkWalker.has_directive(tests[i].non_directives[k]), undefined,
|
|
||||||
"Found directive '" + tests[i].non_directives[k] + "' in test " + tests[i].input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (; i < tests.length; i++) {
|
|
||||||
// Do tests - iterate the ast in each test - check only when _check_ occurs - fail when no _check_ has been found
|
|
||||||
checked = false;
|
|
||||||
var ast = uglify.parse(tests[i].input);
|
|
||||||
ast.walk(checkWalker);
|
|
||||||
if (!checked) {
|
|
||||||
throw "No _check_ symbol found in " + tests[i].input;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("EOF", function() {
|
|
||||||
it("Should test code for at least throwing syntax error when incomplete", function() {
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error;
|
|
||||||
}
|
|
||||||
var parse = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Chops off 1 char at a time until limit or start of string is reached
|
|
||||||
// The passed code must still be valid when unchopped
|
|
||||||
var test_eol = function(input, chopLimit) {
|
|
||||||
if (chopLimit === undefined) {
|
|
||||||
chopLimit = input.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.doesNotThrow(parse(input), "Expected valid code for \n" + input);
|
|
||||||
|
|
||||||
for (var i = input.length - 1; chopLimit > 0; chopLimit--, i--) {
|
|
||||||
var code = input.substr(0, i);
|
|
||||||
assert.throws(parse(code), error, code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_eol("var \\u1234", 7); // Incomplete identifier
|
|
||||||
test_eol("'Incomplete string'");
|
|
||||||
test_eol("/Unterminated regex/");
|
|
||||||
test_eol("` Unterminated template string`");
|
|
||||||
test_eol("/* Unfinishing multiline comment */");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Export", function() {
|
|
||||||
it ("Should parse export directives", function() {
|
|
||||||
|
|
||||||
var inputs = [
|
|
||||||
['export * from "a.js"', ['*'], "a.js"],
|
|
||||||
['export {A} from "a.js"', ['A'], "a.js"],
|
|
||||||
['export {A as X} from "a.js"', ['X'], "a.js"],
|
|
||||||
['export {A as Foo, B} from "a.js"', ['Foo', 'B'], "a.js"],
|
|
||||||
['export {A, B} from "a.js"', ['A', 'B'], "a.js"],
|
|
||||||
];
|
|
||||||
|
|
||||||
var test = function(code) {
|
|
||||||
return uglify.parse(code);
|
|
||||||
};
|
|
||||||
|
|
||||||
var extractNames = function(symbols) {
|
|
||||||
var ret = [];
|
|
||||||
for (var i = 0; i < symbols.length; i++) {
|
|
||||||
ret.push(symbols[i].name.name)
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
|
||||||
var ast = test(inputs[i][0]);
|
|
||||||
var names = inputs[i][1];
|
|
||||||
var filename = inputs[i][2];
|
|
||||||
assert(ast instanceof uglify.AST_Toplevel);
|
|
||||||
assert.equal(ast.body.length, 1);
|
|
||||||
var st = ast.body[0];
|
|
||||||
assert(st instanceof uglify.AST_Export);
|
|
||||||
var actualNames = extractNames(st.exported_names);
|
|
||||||
assert.deepEqual(actualNames, names);
|
|
||||||
assert.equal(st.module_name.value, filename)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Expression", function() {
|
|
||||||
it("Should not allow the first exponentiation operator to be prefixed with an unary operator", function() {
|
|
||||||
var tests = [
|
|
||||||
"+5 ** 3",
|
|
||||||
"-5 ** 3",
|
|
||||||
"~5 ** 3",
|
|
||||||
"!5 ** 3",
|
|
||||||
"void 5 ** 3",
|
|
||||||
"typeof 5 ** 3",
|
|
||||||
"delete 5 ** 3",
|
|
||||||
"var a = -(5) ** 3;"
|
|
||||||
];
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
/^Unexpected token: operator \((?:[!+~-]|void|typeof|delete)\)/.test(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Function", function() {
|
|
||||||
it ("Should parse binding patterns correctly", function() {
|
|
||||||
// Function argument nodes are correct
|
|
||||||
function get_args(args) {
|
|
||||||
return args.map(function (arg) {
|
|
||||||
return [arg.TYPE, arg.name];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructurings as arguments
|
|
||||||
var destr_fun1 = uglify.parse('(function ({a, b}) {})').body[0].body;
|
|
||||||
var destr_fun2 = uglify.parse('(function ([a, [b]]) {})').body[0].body;
|
|
||||||
var destr_fun3 = uglify.parse('({a, b}) => null').body[0].body;
|
|
||||||
var destr_fun4 = uglify.parse('([a, [b]]) => null').body[0].body;
|
|
||||||
|
|
||||||
assert.equal(destr_fun1.argnames.length, 1);
|
|
||||||
assert.equal(destr_fun2.argnames.length, 1);
|
|
||||||
assert.equal(destr_fun3.argnames.length, 1);
|
|
||||||
assert.equal(destr_fun4.argnames.length, 1);
|
|
||||||
|
|
||||||
var destruct1 = destr_fun1.argnames[0];
|
|
||||||
var destruct2 = destr_fun2.argnames[0];
|
|
||||||
var destruct3 = destr_fun3.argnames[0];
|
|
||||||
var destruct4 = destr_fun4.argnames[0];
|
|
||||||
|
|
||||||
assert(destruct1 instanceof uglify.AST_Destructuring);
|
|
||||||
assert(destruct2 instanceof uglify.AST_Destructuring);
|
|
||||||
assert(destruct3 instanceof uglify.AST_Destructuring);
|
|
||||||
assert(destruct4 instanceof uglify.AST_Destructuring);
|
|
||||||
assert(destruct2.names[1] instanceof uglify.AST_Destructuring);
|
|
||||||
assert(destruct4.names[1] instanceof uglify.AST_Destructuring);
|
|
||||||
|
|
||||||
assert.equal(destruct1.start.value, '{');
|
|
||||||
assert.equal(destruct1.end.value, '}');
|
|
||||||
assert.equal(destruct2.start.value, '[');
|
|
||||||
assert.equal(destruct2.end.value, ']');
|
|
||||||
assert.equal(destruct3.start.value, '{');
|
|
||||||
assert.equal(destruct3.end.value, '}');
|
|
||||||
assert.equal(destruct4.start.value, '[');
|
|
||||||
assert.equal(destruct4.end.value, ']');
|
|
||||||
|
|
||||||
assert.equal(destruct1.is_array, false);
|
|
||||||
assert.equal(destruct2.is_array, true);
|
|
||||||
assert.equal(destruct3.is_array, false);
|
|
||||||
assert.equal(destruct4.is_array, true);
|
|
||||||
|
|
||||||
// destruct 1
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct1.names[0].TYPE,
|
|
||||||
destruct1.names[0].key,
|
|
||||||
destruct1.names[0].value.name
|
|
||||||
],
|
|
||||||
['ObjectKeyVal', 'a', 'a']
|
|
||||||
);
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct1.names[1].TYPE,
|
|
||||||
destruct1.names[1].key,
|
|
||||||
destruct1.names[1].value.name
|
|
||||||
],
|
|
||||||
['ObjectKeyVal', 'b', 'b']
|
|
||||||
);
|
|
||||||
|
|
||||||
// destruct 2
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct2.names[0].TYPE,
|
|
||||||
destruct2.names[0].name
|
|
||||||
],
|
|
||||||
['SymbolFunarg', 'a']
|
|
||||||
);
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct2.names[1].names[0].TYPE,
|
|
||||||
destruct2.names[1].names[0].name
|
|
||||||
],
|
|
||||||
['SymbolFunarg', 'b']
|
|
||||||
);
|
|
||||||
|
|
||||||
// destruct 3
|
|
||||||
assert.strictEqual(typeof destruct3.names[0].key, "string");
|
|
||||||
assert.strictEqual(destruct3.names[0].key, "a");
|
|
||||||
assert.strictEqual(destruct3.names[0].value.TYPE, "SymbolFunarg");
|
|
||||||
assert.strictEqual(destruct3.names[0].value.name, "a");
|
|
||||||
assert.strictEqual(typeof destruct3.names[1].key, "string");
|
|
||||||
assert.strictEqual(destruct3.names[1].key, "b");
|
|
||||||
assert.strictEqual(destruct3.names[1].value.TYPE, "SymbolFunarg");
|
|
||||||
assert.strictEqual(destruct3.names[1].value.name, "b");
|
|
||||||
|
|
||||||
// destruct 4
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct4.names[0].TYPE,
|
|
||||||
destruct4.names[0].name
|
|
||||||
],
|
|
||||||
['SymbolFunarg', 'a']
|
|
||||||
);
|
|
||||||
assert.strictEqual(destruct4.names[1].TYPE, "Destructuring");
|
|
||||||
assert.deepEqual(
|
|
||||||
[
|
|
||||||
destruct4.names[1].names[0].TYPE,
|
|
||||||
destruct4.names[1].names[0].name
|
|
||||||
],
|
|
||||||
['SymbolFunarg', 'b']
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(
|
|
||||||
get_args(destr_fun1.args_as_names()),
|
|
||||||
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
|
||||||
);
|
|
||||||
assert.deepEqual(
|
|
||||||
get_args(destr_fun2.args_as_names()),
|
|
||||||
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
|
||||||
);
|
|
||||||
assert.deepEqual(
|
|
||||||
get_args(destr_fun3.args_as_names()),
|
|
||||||
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
|
||||||
);
|
|
||||||
assert.deepEqual(
|
|
||||||
get_args(destr_fun4.args_as_names()),
|
|
||||||
[['SymbolFunarg', 'a'], ['SymbolFunarg', 'b']]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Making sure we don't accidentally accept things which
|
|
||||||
// Aren't argument destructurings
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('(function ( { a, [ b ] } ) { })')
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('(function (1) { })');
|
|
||||||
}, /Invalid function parameter/);
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('(function (this) { })');
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('(function ([1]) { })');
|
|
||||||
}, /Invalid function parameter/);
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('(function [a] { })');
|
|
||||||
});
|
|
||||||
|
|
||||||
// generators
|
|
||||||
var generators_def = uglify.parse('function* fn() {}').body[0];
|
|
||||||
assert.equal(generators_def.is_generator, true);
|
|
||||||
|
|
||||||
assert.throws(function () {
|
|
||||||
uglify.parse('function* (){ }');
|
|
||||||
});
|
|
||||||
|
|
||||||
var generators_yield_def = uglify.parse('function* fn() {\nyield remote();\}').body[0].body[0];
|
|
||||||
assert.strictEqual(generators_yield_def.body.is_star, false);
|
|
||||||
});
|
|
||||||
it("Should not accept spread on non-last parameters", function() {
|
|
||||||
var tests = [
|
|
||||||
"var a = function(...a, b) { return a.join(b) }",
|
|
||||||
"var b = function(a, b, ...c, d) { return c.join(a + b) + d }",
|
|
||||||
"function foo(...a, b) { return a.join(b) }",
|
|
||||||
"function bar(a, b, ...c, d) { return c.join(a + b) + d }",
|
|
||||||
"var a = function*(...a, b) { return a.join(b) }",
|
|
||||||
"var b = function*(a, b, ...c, d) { return c.join(a + b) + d }",
|
|
||||||
"function* foo(...a, b) { return a.join(b) }",
|
|
||||||
"function* bar(a, b, ...c, d) { return c.join(a + b) + d }"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
/^Unexpected token: /.test(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should not accept empty parameters after elision", function() {
|
|
||||||
var tests = [
|
|
||||||
"(function(,){})()",
|
|
||||||
"(function(a,){})()",
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === "Invalid function parameter";
|
|
||||||
}
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should not accept an initializer when parameter is a rest parameter", function() {
|
|
||||||
var tests = [
|
|
||||||
"(function(...a = b){})()",
|
|
||||||
"(function(a, ...b = [c, d]))"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function () {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function (e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Shoult not accept duplicated identifiers inside parameters in strict mode or when using default assigment or spread", function() {
|
|
||||||
// From: ES2016 9.2.12 FunctionDeclarationInstantiation (func, argumentsList)
|
|
||||||
// NOTE Early errors ensure that duplicate parameter names can only occur
|
|
||||||
// in non-strict functions that do not have parameter default values or
|
|
||||||
// rest parameters.
|
|
||||||
var tests = [
|
|
||||||
"(function(a = 1, a){})()",
|
|
||||||
"(function(a, [a = 3]){})()",
|
|
||||||
"(function(a, b, c, d, [{e: [...a]}]){})()",
|
|
||||||
"'use strict'; (function(a, a){})",
|
|
||||||
"(function({a, a = b}))",
|
|
||||||
"(function(a, [...a]){})",
|
|
||||||
"(function(a, ...a){})",
|
|
||||||
"(function(a, [a, ...b]){})",
|
|
||||||
"(function(a, {b: a, c: [...d]}){})",
|
|
||||||
"(function(a, a, {b: [...c]}){})"
|
|
||||||
];
|
|
||||||
var test = function(code) {
|
|
||||||
return function () {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function (e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
/^Parameter [a-zA-Z]+ was used already$/.test(e.message);
|
|
||||||
}
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -71,7 +71,7 @@ describe("Getters and setters", function() {
|
|||||||
var fail = function(data) {
|
var fail = function(data) {
|
||||||
return function (e) {
|
return function (e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
/^Unexpected token: /.test(e.message);
|
e.message === "Unexpected token: operator (" + data.operator + ")";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,265 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Left-hand side expressions", function () {
|
|
||||||
it("Should parse destructuring with const/let/var correctly", function () {
|
|
||||||
var decls = uglify.parse('var {a,b} = foo, { c, d } = bar');
|
|
||||||
|
|
||||||
assert.equal(decls.body[0].TYPE, 'Var');
|
|
||||||
assert.equal(decls.body[0].definitions.length, 2);
|
|
||||||
|
|
||||||
// Item 1
|
|
||||||
assert.equal(decls.body[0].definitions[0].name.TYPE, 'Destructuring');
|
|
||||||
assert.equal(decls.body[0].definitions[0].value.TYPE, 'SymbolRef');
|
|
||||||
|
|
||||||
// Item 2
|
|
||||||
assert.equal(decls.body[0].definitions[1].name.TYPE, 'Destructuring');
|
|
||||||
assert.equal(decls.body[0].definitions[1].value.TYPE, 'SymbolRef');
|
|
||||||
|
|
||||||
var nested_def = uglify.parse('var [{x}] = foo').body[0].definitions[0];
|
|
||||||
|
|
||||||
assert.equal(nested_def.name.names[0].names[0].TYPE, 'ObjectKeyVal');
|
|
||||||
assert.equal(nested_def.name.names[0].names[0].value.TYPE, 'SymbolVar');
|
|
||||||
assert.equal(nested_def.name.names[0].names[0].key, 'x');
|
|
||||||
assert.equal(nested_def.name.names[0].names[0].value.name, 'x');
|
|
||||||
|
|
||||||
var holey_def = uglify.parse('const [,,third] = [1,2,3]').body[0].definitions[0];
|
|
||||||
|
|
||||||
assert.equal(holey_def.name.names[0].TYPE, 'Hole');
|
|
||||||
assert.equal(holey_def.name.names[1].TYPE, 'Hole');
|
|
||||||
assert.equal(holey_def.name.names[2].TYPE, 'SymbolConst');
|
|
||||||
|
|
||||||
var expanding_def = uglify.parse('var [first, ...rest] = [1,2,3]').body[0].definitions[0];
|
|
||||||
|
|
||||||
assert.equal(expanding_def.name.names[0].TYPE, 'SymbolVar');
|
|
||||||
assert.equal(expanding_def.name.names[1].TYPE, 'Expansion');
|
|
||||||
assert.equal(expanding_def.name.names[1].expression.TYPE, 'SymbolVar');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Parser should use AST_Array for array literals", function() {
|
|
||||||
var ast = uglify.parse('["foo", "bar"]');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Array);
|
|
||||||
|
|
||||||
ast = uglify.parse('a = ["foo"]');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Parser should use AST_Object for object literals", function() {
|
|
||||||
var ast = uglify.parse('({foo: "bar"})');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Object);
|
|
||||||
|
|
||||||
// This example should be fine though
|
|
||||||
ast = uglify.parse('a = {foo: "bar"}');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Object);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Parser should use AST_Destructuring for array assignment patterns", function() {
|
|
||||||
var ast = uglify.parse('[foo, bar] = [1, 2]');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Parser should use AST_Destructuring for object assignment patterns", function() {
|
|
||||||
var ast = uglify.parse('({a: b, b: c} = {b: "c", c: "d"})');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Object);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Parser should be able to handle nested destructuring", function() {
|
|
||||||
var ast = uglify.parse('[{a,b},[d, e, f, {g, h}]] = [{a: 1, b: 2}, [3, 4, 5, {g: 6, h: 7}]]');
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].is_array, false);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[1].is_array, true);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1].names[3] instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[1].names[3].is_array, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should handle spread operator in destructuring", function() {
|
|
||||||
var ast = uglify.parse("[a, b, ...c] = [1, 2, 3, 4, 5]");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_Array);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
|
||||||
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[2] instanceof uglify.AST_Expansion);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should handle default assignments in destructuring", function() {
|
|
||||||
var ast = uglify.parse("({x: v, z = z + 5} = obj);");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].start.value, "x");
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[1].start.value, "z");
|
|
||||||
assert(ast.body[0].body.left.names[1].value.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[1].value.operator, "=");
|
|
||||||
assert(ast.body[0].body.left.names[1].value.right instanceof uglify.AST_Binary);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("({x = 123} = obj);");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].body.left.names[0].value.left instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
|
|
||||||
ast = uglify.parse("[x, y = 5] = foo");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].start.value, "x");
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].body.left.names[1].left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[1].start.value, "y");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should handle default assignments containing assignments in a destructuring", function() {
|
|
||||||
var ast = uglify.parse("[x, y = z = 2] = a;");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, true);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1] instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].body.left.names[1].left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.equal(ast.body[0].body.left.names[1].operator, "=");
|
|
||||||
assert(ast.body[0].body.left.names[1].right instanceof uglify.AST_Assign);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[1].right.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.equal(ast.body[0].body.left.names[1].right.operator, "=");
|
|
||||||
assert(ast.body[0].body.left.names[1].right.right instanceof uglify.AST_Number);
|
|
||||||
|
|
||||||
ast = uglify.parse("({a: a = 123} = obj)");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
assert(ast.body[0].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[0].body.left instanceof uglify.AST_Destructuring);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.is_array, false);
|
|
||||||
assert.equal(ast.body[0].body.operator, "=");
|
|
||||||
assert(ast.body[0].body.right instanceof uglify.AST_SymbolRef);
|
|
||||||
|
|
||||||
assert(ast.body[0].body.left.names[0] instanceof uglify.AST_ObjectProperty);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].key, "a");
|
|
||||||
assert(ast.body[0].body.left.names[0].value instanceof uglify.AST_DefaultAssign);
|
|
||||||
assert(ast.body[0].body.left.names[0].value.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.strictEqual(ast.body[0].body.left.names[0].value.operator, "=");
|
|
||||||
assert(ast.body[0].body.left.names[0].value.right instanceof uglify.AST_Number);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should allow multiple spread in array literals", function() {
|
|
||||||
var ast = uglify.parse("var a = [1, 2, 3], b = [4, 5, 6], joined; joined = [...a, ...b]");
|
|
||||||
assert(ast.body[0] instanceof uglify.AST_Var);
|
|
||||||
assert(ast.body[1] instanceof uglify.AST_SimpleStatement);
|
|
||||||
|
|
||||||
// Check statement containing array with spreads
|
|
||||||
assert(ast.body[1].body instanceof uglify.AST_Assign);
|
|
||||||
assert(ast.body[1].body.left instanceof uglify.AST_SymbolRef);
|
|
||||||
assert.equal(ast.body[1].body.operator, "=");
|
|
||||||
assert(ast.body[1].body.right instanceof uglify.AST_Array);
|
|
||||||
|
|
||||||
// Check array content
|
|
||||||
assert.strictEqual(ast.body[1].body.right.elements.length, 2);
|
|
||||||
assert(ast.body[1].body.right.elements[0] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[1].body.right.elements[0].expression instanceof uglify.AST_SymbolRef);
|
|
||||||
assert(ast.body[1].body.right.elements[0].expression.name, "a");
|
|
||||||
assert(ast.body[1].body.right.elements[1] instanceof uglify.AST_Expansion);
|
|
||||||
assert(ast.body[1].body.right.elements[1].expression instanceof uglify.AST_SymbolRef);
|
|
||||||
assert(ast.body[1].body.right.elements[1].expression.name, "b");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow spread on invalid locations", function() {
|
|
||||||
var expect = function(input, expected) {
|
|
||||||
var execute = function(input) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var check = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
|
||||||
e.message === expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.throws(execute(input), check);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spreads are not allowed in destructuring array if it's not the last element
|
|
||||||
expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array");
|
|
||||||
|
|
||||||
// Multiple spreads are not allowed in destructuring array
|
|
||||||
expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array");
|
|
||||||
|
|
||||||
// Spread in obvious object pattern
|
|
||||||
expect("({...a} = foo)", "Unexpected token: expand (...)");
|
|
||||||
|
|
||||||
// Spread in block should not be allowed
|
|
||||||
expect("{...a} = foo", "Unexpected token: expand (...)");
|
|
||||||
|
|
||||||
// Not in standard yet
|
|
||||||
expect("let foo = {bar: 42}, bar; bar = {...foo}", "Unexpected token: expand (...)");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var uglify = require("../node");
|
var uglify = require("../../");
|
||||||
|
|
||||||
describe("New", function() {
|
describe("New", function() {
|
||||||
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
|
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
|
||||||
@@ -83,11 +83,4 @@ describe("New", function() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should check target in new.target", function() {
|
|
||||||
assert.throws(function() {uglify.parse("new.blah")}, function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "Unexpected token name «blah», expected name «target»";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
var Uglify = require("../node");
|
|
||||||
var assert = require("assert");
|
|
||||||
|
|
||||||
describe("Object", function() {
|
|
||||||
it("Should allow objects to have a methodDefinition as property", function() {
|
|
||||||
var code = "var a = {test() {return true;}}";
|
|
||||||
assert.equal(Uglify.minify(code).code, "var a={test(){return!0}};");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow objects to use static keywords like in classes", function() {
|
|
||||||
var code = "{static test() {}}";
|
|
||||||
var parse = function() {
|
|
||||||
Uglify.parse(code);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof Uglify.JS_Parse_Error;
|
|
||||||
}
|
|
||||||
assert.throws(parse, expect);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow objects to have static computed properties like in classes", function() {
|
|
||||||
var code = "var foo = {static [123](){}}";
|
|
||||||
var parse = function() {
|
|
||||||
console.log(Uglify.parse(code).body[0].body[0]);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof Uglify.JS_Parse_Error;
|
|
||||||
}
|
|
||||||
assert.throws(parse, expect);
|
|
||||||
});
|
|
||||||
it("Should not accept operator tokens as property/getter/setter name", function() {
|
|
||||||
var illegalOperators = [
|
|
||||||
"++",
|
|
||||||
"--",
|
|
||||||
"+",
|
|
||||||
"-",
|
|
||||||
"!",
|
|
||||||
"~",
|
|
||||||
"&",
|
|
||||||
"|",
|
|
||||||
"^",
|
|
||||||
"*",
|
|
||||||
"/",
|
|
||||||
"%",
|
|
||||||
">>",
|
|
||||||
"<<",
|
|
||||||
">>>",
|
|
||||||
"<",
|
|
||||||
">",
|
|
||||||
"<=",
|
|
||||||
">=",
|
|
||||||
"==",
|
|
||||||
"===",
|
|
||||||
"!=",
|
|
||||||
"!==",
|
|
||||||
"?",
|
|
||||||
"=",
|
|
||||||
"+=",
|
|
||||||
"-=",
|
|
||||||
"/=",
|
|
||||||
"*=",
|
|
||||||
"%=",
|
|
||||||
">>=",
|
|
||||||
"<<=",
|
|
||||||
">>>=",
|
|
||||||
"|=",
|
|
||||||
"^=",
|
|
||||||
"&=",
|
|
||||||
"&&",
|
|
||||||
"||"
|
|
||||||
];
|
|
||||||
var generator = function() {
|
|
||||||
var results = [];
|
|
||||||
|
|
||||||
for (var i in illegalOperators) {
|
|
||||||
results.push({
|
|
||||||
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
|
|
||||||
operator: illegalOperators[i],
|
|
||||||
method: "get"
|
|
||||||
});
|
|
||||||
results.push({
|
|
||||||
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
|
|
||||||
operator: illegalOperators[i],
|
|
||||||
method: "set"
|
|
||||||
});
|
|
||||||
results.push({
|
|
||||||
code: "var obj = { " + illegalOperators[i] + ': "123"};',
|
|
||||||
operator: illegalOperators[i],
|
|
||||||
method: "key"
|
|
||||||
});
|
|
||||||
results.push({
|
|
||||||
code: "var obj = { " + illegalOperators[i] + "(){ return test; }};",
|
|
||||||
operator: illegalOperators[i],
|
|
||||||
method: "method"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
var testCase = function(data) {
|
|
||||||
return function() {
|
|
||||||
Uglify.parse(data.code);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var fail = function(data) {
|
|
||||||
return function (e) {
|
|
||||||
return e instanceof Uglify.JS_Parse_Error && (
|
|
||||||
e.message === "Unexpected token: operator (" + data.operator + ")" ||
|
|
||||||
(e.message === "Unterminated regular expression" && data.operator[0] === "/") ||
|
|
||||||
(e.message === "Unexpected token: punc (()" && data.operator === "*")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var errorMessage = function(data) {
|
|
||||||
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
|
|
||||||
};
|
|
||||||
|
|
||||||
var tests = generator();
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
var test = tests[i];
|
|
||||||
assert.throws(testCase(test), fail(test), errorMessage(test));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Should be able to use shorthand properties", function() {
|
|
||||||
var ast = Uglify.parse("var foo = 123\nvar obj = {foo: foo}");
|
|
||||||
assert.strictEqual(ast.print_to_string({ecma: 6}), "var foo=123;var obj={foo};");
|
|
||||||
})
|
|
||||||
});
|
|
||||||
@@ -4,7 +4,7 @@ var uglify = require("../node");
|
|||||||
|
|
||||||
describe("spidermonkey export/import sanity test", function() {
|
describe("spidermonkey export/import sanity test", function() {
|
||||||
it("should produce a functional build when using --self with spidermonkey", function(done) {
|
it("should produce a functional build when using --self with spidermonkey", function(done) {
|
||||||
this.timeout(20000);
|
this.timeout(30000);
|
||||||
|
|
||||||
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
|
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||||
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
|
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
|
||||||
@@ -15,7 +15,9 @@ describe("spidermonkey export/import sanity test", function() {
|
|||||||
|
|
||||||
eval(stdout);
|
eval(stdout);
|
||||||
assert.strictEqual(typeof SpiderUglify, "object");
|
assert.strictEqual(typeof SpiderUglify, "object");
|
||||||
assert.strictEqual(SpiderUglify.minify("foo([true,,2+3]);").code, "foo([!0,,5]);");
|
var result = SpiderUglify.minify("foo([true,,2+3]);");
|
||||||
|
assert.strictEqual(result.error, undefined);
|
||||||
|
assert.strictEqual(result.code, "foo([!0,,5]);");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Template string", function() {
|
|
||||||
it("Should not accept invalid sequences", function() {
|
|
||||||
var tests = [
|
|
||||||
// Stress invalid expression
|
|
||||||
"var foo = `Hello ${]}`",
|
|
||||||
"var foo = `Test 123 ${>}`",
|
|
||||||
"var foo = `Blah ${;}`",
|
|
||||||
|
|
||||||
// Stress invalid template_substitution after expression
|
|
||||||
"var foo = `Blablabla ${123 456}`",
|
|
||||||
"var foo = `Blub ${123;}`",
|
|
||||||
"var foo = `Bleh ${a b}`"
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& /^Unexpected token: /.test(e.message);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Try", function() {
|
|
||||||
it("Should not allow catch with an empty parameter", function() {
|
|
||||||
var tests = [
|
|
||||||
"try {} catch() {}"
|
|
||||||
];
|
|
||||||
|
|
||||||
var test = function(code) {
|
|
||||||
return function () {
|
|
||||||
uglify.parse(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var error = function (e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), error, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
var assert = require("assert");
|
|
||||||
var uglify = require("../node");
|
|
||||||
|
|
||||||
describe("Unicode", function() {
|
|
||||||
it("Should not accept invalid code ranges in unicode escape", function() {
|
|
||||||
var tests = [
|
|
||||||
"\\u{110000}", // A bit over the unicode range
|
|
||||||
"\\u{100000061} = 'foo'", // 32-bit overflow resulting in "a"
|
|
||||||
"\\u{fffffffffff}", // A bit too much over the unicode range
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "Unicode reference out of bounce";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not accept invalid unicode sequences", function() {
|
|
||||||
var tests = [
|
|
||||||
"var foo = '\\u-111'",
|
|
||||||
"var bar = '\\u{-1}'",
|
|
||||||
"var baz = '\\ugggg'"
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "Invalid hex-character pattern in string";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should throw error if escaped first identifier char is not part of ID_start", function() {
|
|
||||||
var tests = [
|
|
||||||
'var \\u{0} = "foo";',
|
|
||||||
'var \\u{10ffff} = "bar";',
|
|
||||||
'var \\u000a = "what\'s up";',
|
|
||||||
// Valid ID_Start, but using up 2 escaped characters and not fitting in IdentifierStart
|
|
||||||
'var \\ud800\\udc00 = "Hello";',
|
|
||||||
'var \\udbff\\udfff = "Unicode";', // Same as previous test
|
|
||||||
'var \\ud800\udc01 = "Weird unicode";', // Same as above, but mixed escaped with unicode chars
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "First identifier char is an invalid identifier char";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should throw error if escaped non-first identifier char is not part of ID_start", function() {
|
|
||||||
var tests = [
|
|
||||||
'var a\\u{0} = "foo";',
|
|
||||||
'var a\\u{10ffff} = "bar";',
|
|
||||||
'var z\\u000a = "what\'s up";'
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "Invalid escaped identifier char";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should throw error if identifier is a keyword with a escape sequences", function() {
|
|
||||||
var tests = [
|
|
||||||
'var \\u0069\\u006e = "foo"', // in
|
|
||||||
'var \\u0076\\u0061\\u0072 = "bar"', // var
|
|
||||||
'var \\u{66}\\u{6f}\\u{72} = "baz"', // for
|
|
||||||
'var \\u0069\\u{66} = "foobar"', // if
|
|
||||||
'var \\u{73}uper' // super
|
|
||||||
];
|
|
||||||
|
|
||||||
var exec = function(test) {
|
|
||||||
return function() {
|
|
||||||
uglify.parse(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof uglify.JS_Parse_Error
|
|
||||||
&& e.message === "Escaped characters are not allowed in keywords";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(exec(tests[i]), fail);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should read strings containing surigates correctly", function() {
|
|
||||||
var tests = [
|
|
||||||
['var a = "\ud800\udc00";', 'var a="\\u{10000}";'],
|
|
||||||
['var b = "\udbff\udfff";', 'var b="\\u{10ffff}";']
|
|
||||||
];
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.strictEqual(uglify.minify(tests[i][0], {
|
|
||||||
output: { ascii_only: true, ecma: 6 }
|
|
||||||
}).code, tests[i][1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should parse raw characters correctly", function() {
|
|
||||||
var ast = uglify.parse('console.log("\\udbff");');
|
|
||||||
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");');
|
|
||||||
ast = uglify.parse(ast.print_to_string());
|
|
||||||
assert.strictEqual(ast.print_to_string(), 'console.log("\udbff");');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
var UglifyJS = require("../node");
|
|
||||||
var assert = require("assert");
|
|
||||||
|
|
||||||
describe("Yield", function() {
|
|
||||||
it("Should not delete statements after yield", function() {
|
|
||||||
var js = 'function *foo(bar) { yield 1; yield 2; return 3; }';
|
|
||||||
var result = UglifyJS.minify(js);
|
|
||||||
assert.strictEqual(result.code, 'function*foo(e){return yield 1,yield 2,3}');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow yield as labelIdentifier within generators", function() {
|
|
||||||
var js = "function* g() {yield: 1}"
|
|
||||||
var test = function() {
|
|
||||||
UglifyJS.parse(js);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
|
||||||
e.message === "Yield cannot be used as label inside generators";
|
|
||||||
}
|
|
||||||
assert.throws(test, expect);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow yield* followed by a semicolon in generators", function() {
|
|
||||||
var js = "function* test() {yield*\n;}";
|
|
||||||
var test = function() {
|
|
||||||
UglifyJS.parse(js);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected token: punc (;)";
|
|
||||||
}
|
|
||||||
assert.throws(test, expect);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow yield with next token star on next line", function() {
|
|
||||||
var js = "function* test() {yield\n*123;}";
|
|
||||||
var test = function() {
|
|
||||||
UglifyJS.parse(js);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
|
||||||
e.message === "Unexpected token: operator (*)";
|
|
||||||
}
|
|
||||||
assert.throws(test, expect);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should be able to compress its expression", function() {
|
|
||||||
assert.strictEqual(
|
|
||||||
UglifyJS.minify("function *f() { yield 3-4; }", {compress: true}).code,
|
|
||||||
"function*f(){yield-1}"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should keep undefined after yield without compression if found in ast", function() {
|
|
||||||
assert.strictEqual(
|
|
||||||
UglifyJS.minify("function *f() { yield undefined; yield; yield* undefined; yield void 0}", {compress: false}).code,
|
|
||||||
"function*f(){yield undefined;yield;yield*undefined;yield void 0}"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should be able to drop undefined after yield if necessary with compression", function() {
|
|
||||||
assert.strictEqual(
|
|
||||||
UglifyJS.minify("function *f() { yield undefined; yield; yield* undefined; yield void 0}", {compress: true}).code,
|
|
||||||
"function*f(){yield,yield,yield*void 0,yield}"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow yield to be used as symbol, identifier or property outside generators in strict mode", function() {
|
|
||||||
var tests = [
|
|
||||||
// Fail as as_symbol
|
|
||||||
'"use strict"; import yield from "bar";',
|
|
||||||
'"use strict"; yield = 123;',
|
|
||||||
'"use strict"; yield: "123";',
|
|
||||||
'"use strict"; for(;;){break yield;}',
|
|
||||||
'"use strict"; for(;;){continue yield;}',
|
|
||||||
'"use strict"; function yield(){}',
|
|
||||||
'"use strict"; function foo(...yield){}',
|
|
||||||
'"use strict"; try { new Error("")} catch (yield) {}',
|
|
||||||
'"use strict"; var yield = "foo";',
|
|
||||||
'"use strict"; class yield {}',
|
|
||||||
|
|
||||||
// Fail as maybe_assign
|
|
||||||
'"use strict"; var foo = yield;',
|
|
||||||
'"use strict"; var foo = bar = yield',
|
|
||||||
|
|
||||||
// Fail as as_property_name
|
|
||||||
'"use strict"; var foo = {yield};',
|
|
||||||
'"use strict"; var bar = {yield: "foo"};'
|
|
||||||
];
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
|
||||||
/^Unexpected yield identifier (?:as parameter )?inside strict mode/.test(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
var test = function(input) {
|
|
||||||
return function() {
|
|
||||||
UglifyJS.parse(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
assert.throws(test(tests[i]), fail, tests[i]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,103 +1,73 @@
|
|||||||
// Testing UglifyJS <-> SpiderMonkey AST conversion
|
// Testing UglifyJS <-> SpiderMonkey AST conversion
|
||||||
// through generative testing.
|
"use strict";
|
||||||
|
|
||||||
var UglifyJS = require("./node"),
|
var acorn = require("acorn");
|
||||||
escodegen = require("escodegen"),
|
var ufuzz = require("./ufuzz");
|
||||||
esfuzz = require("esfuzz"),
|
var UglifyJS = require("..");
|
||||||
estraverse = require("estraverse"),
|
|
||||||
prefix = "\r ";
|
|
||||||
|
|
||||||
// Normalizes input AST for UglifyJS in order to get correct comparison.
|
function try_beautify(code) {
|
||||||
|
var beautified = UglifyJS.minify(code, {
|
||||||
function normalizeInput(ast) {
|
compress: false,
|
||||||
return estraverse.replace(ast, {
|
mangle: false,
|
||||||
enter: function(node, parent) {
|
output: {
|
||||||
switch (node.type) {
|
beautify: true,
|
||||||
// Internally mark all the properties with semi-standard type "Property".
|
bracketize: true
|
||||||
case "ObjectExpression":
|
|
||||||
node.properties.forEach(function (property) {
|
|
||||||
property.type = "Property";
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Since UglifyJS doesn"t recognize different types of property keys,
|
|
||||||
// decision on SpiderMonkey node type is based on check whether key
|
|
||||||
// can be valid identifier or not - so we do in input AST.
|
|
||||||
case "Property":
|
|
||||||
var key = node.key;
|
|
||||||
if (key.type === "Literal" && typeof key.value === "string" && UglifyJS.is_identifier(key.value)) {
|
|
||||||
node.key = {
|
|
||||||
type: "Identifier",
|
|
||||||
name: key.value
|
|
||||||
};
|
|
||||||
} else if (key.type === "Identifier" && !UglifyJS.is_identifier(key.name)) {
|
|
||||||
node.key = {
|
|
||||||
type: "Literal",
|
|
||||||
value: key.name
|
|
||||||
};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// UglifyJS internally flattens all the expression sequences - either
|
|
||||||
// to one element (if sequence contains only one element) or flat list.
|
|
||||||
case "SequenceExpression":
|
|
||||||
node.expressions = node.expressions.reduce(function flatten(list, expr) {
|
|
||||||
return list.concat(expr.type === "SequenceExpression" ? expr.expressions.reduce(flatten, []) : [expr]);
|
|
||||||
}, []);
|
|
||||||
if (node.expressions.length === 1) {
|
|
||||||
return node.expressions[0];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (beautified.error) {
|
||||||
|
console.log("// !!! beautify failed !!!");
|
||||||
|
console.log(beautified.error.stack);
|
||||||
|
console.log(code);
|
||||||
|
} else {
|
||||||
|
console.log("// (beautified)");
|
||||||
|
console.log(beautified.code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(options) {
|
function test(original, estree, description) {
|
||||||
console.log("--- UglifyJS <-> Mozilla AST conversion");
|
var transformed = UglifyJS.minify(UglifyJS.AST_Node.from_mozilla_ast(estree), {
|
||||||
|
compress: false,
|
||||||
for (var counter = 0; counter < options.iterations; counter++) {
|
mangle: false
|
||||||
process.stdout.write(prefix + counter + "/" + options.iterations);
|
});
|
||||||
|
if (transformed.error || original !== transformed.code) {
|
||||||
var ast1 = normalizeInput(esfuzz.generate({
|
console.log("//=============================================================");
|
||||||
maxDepth: options.maxDepth
|
console.log("// !!!!!! Failed... round", round);
|
||||||
}));
|
console.log("// original code");
|
||||||
|
try_beautify(original);
|
||||||
var ast2 =
|
console.log();
|
||||||
UglifyJS
|
console.log();
|
||||||
.AST_Node
|
console.log("//-------------------------------------------------------------");
|
||||||
.from_mozilla_ast(ast1)
|
console.log("//", description);
|
||||||
.to_mozilla_ast();
|
if (transformed.error) {
|
||||||
|
console.log(transformed.error.stack);
|
||||||
var astPair = [
|
} else {
|
||||||
{name: 'expected', value: ast1},
|
try_beautify(transformed.code);
|
||||||
{name: 'actual', value: ast2}
|
|
||||||
];
|
|
||||||
|
|
||||||
var jsPair = astPair.map(function(item) {
|
|
||||||
return {
|
|
||||||
name: item.name,
|
|
||||||
value: escodegen.generate(item.value)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (jsPair[0].value !== jsPair[1].value) {
|
|
||||||
var fs = require("fs");
|
|
||||||
var acorn = require("acorn");
|
|
||||||
|
|
||||||
fs.existsSync("tmp") || fs.mkdirSync("tmp");
|
|
||||||
|
|
||||||
jsPair.forEach(function (item) {
|
|
||||||
var fileName = "tmp/dump_" + item.name;
|
|
||||||
var ast = acorn.parse(item.value);
|
|
||||||
fs.writeFileSync(fileName + ".js", item.value);
|
|
||||||
fs.writeFileSync(fileName + ".json", JSON.stringify(ast, null, 2));
|
|
||||||
});
|
|
||||||
|
|
||||||
process.stdout.write("\n");
|
|
||||||
throw new Error("Got different outputs, check out tmp/dump_*.{js,json} for codes and ASTs.");
|
|
||||||
}
|
}
|
||||||
|
console.log("!!!!!! Failed... round", round);
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
|
var num_iterations = ufuzz.num_iterations;
|
||||||
};
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
|
var code = ufuzz.createTopLevelCode();
|
||||||
|
var uglified = UglifyJS.minify(code, {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
ast: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
|
||||||
|
try {
|
||||||
|
test(uglified.code, acorn.parse(code), "acorn.parse()");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("//=============================================================");
|
||||||
|
console.log("// acorn parser failed... round", round);
|
||||||
|
console.log(e);
|
||||||
|
console.log("// original code");
|
||||||
|
console.log(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ var path = require("path");
|
|||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var sandbox = require("./sandbox");
|
var sandbox = require("./sandbox");
|
||||||
|
var semver = require("semver");
|
||||||
|
|
||||||
var tests_dir = path.dirname(module.filename);
|
var tests_dir = path.dirname(module.filename);
|
||||||
var failures = 0;
|
var failures = 0;
|
||||||
@@ -23,12 +24,6 @@ mocha_tests();
|
|||||||
var run_sourcemaps_tests = require('./sourcemaps');
|
var run_sourcemaps_tests = require('./sourcemaps');
|
||||||
run_sourcemaps_tests();
|
run_sourcemaps_tests();
|
||||||
|
|
||||||
var run_ast_conversion_tests = require("./mozilla-ast");
|
|
||||||
|
|
||||||
run_ast_conversion_tests({
|
|
||||||
iterations: 1000
|
|
||||||
});
|
|
||||||
|
|
||||||
/* -----[ utils ]----- */
|
/* -----[ utils ]----- */
|
||||||
|
|
||||||
function tmpl() {
|
function tmpl() {
|
||||||
@@ -170,7 +165,8 @@ function run_compress_tests() {
|
|||||||
failed_files[file] = 1;
|
failed_files[file] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (test.expect_stdout) {
|
if (test.expect_stdout
|
||||||
|
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||||
var stdout = sandbox.run_code(input_code);
|
var stdout = sandbox.run_code(input_code);
|
||||||
if (test.expect_stdout === true) {
|
if (test.expect_stdout === true) {
|
||||||
test.expect_stdout = stdout;
|
test.expect_stdout = stdout;
|
||||||
@@ -280,7 +276,14 @@ function parse_test(file) {
|
|||||||
if (node instanceof U.AST_LabeledStatement) {
|
if (node instanceof U.AST_LabeledStatement) {
|
||||||
var label = node.label;
|
var label = node.label;
|
||||||
assert.ok(
|
assert.ok(
|
||||||
["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0,
|
[
|
||||||
|
"input",
|
||||||
|
"expect",
|
||||||
|
"expect_exact",
|
||||||
|
"expect_warnings",
|
||||||
|
"expect_stdout",
|
||||||
|
"node_version",
|
||||||
|
].indexOf(label.name) >= 0,
|
||||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
name: label.name,
|
name: label.name,
|
||||||
line: label.start.line,
|
line: label.start.line,
|
||||||
@@ -288,7 +291,7 @@ function parse_test(file) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
var stat = node.body;
|
var stat = node.body;
|
||||||
if (label.name == "expect_exact") {
|
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||||
test[label.name] = read_string(stat);
|
test[label.name] = read_string(stat);
|
||||||
} else if (label.name == "expect_stdout") {
|
} else if (label.name == "expect_stdout") {
|
||||||
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
|
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
|
var semver = require("semver");
|
||||||
var vm = require("vm");
|
var vm = require("vm");
|
||||||
|
|
||||||
function safe_log(arg) {
|
function safe_log(arg, level) {
|
||||||
if (arg) switch (typeof arg) {
|
if (arg) switch (typeof arg) {
|
||||||
case "function":
|
case "function":
|
||||||
return arg.toString();
|
return arg.toString();
|
||||||
case "object":
|
case "object":
|
||||||
if (/Error$/.test(arg.name)) return arg.toString();
|
if (/Error$/.test(arg.name)) return arg.toString();
|
||||||
arg.constructor.toString();
|
arg.constructor.toString();
|
||||||
for (var key in arg) {
|
if (level--) for (var key in arg) {
|
||||||
arg[key] = safe_log(arg[key]);
|
if (!Object.getOwnPropertyDescriptor(arg, key).get) {
|
||||||
|
arg[key] = safe_log(arg[key], level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arg;
|
return arg;
|
||||||
@@ -48,7 +51,9 @@ exports.run_code = function(code) {
|
|||||||
].join("\n"), {
|
].join("\n"), {
|
||||||
console: {
|
console: {
|
||||||
log: function() {
|
log: function() {
|
||||||
return console.log.apply(console, [].map.call(arguments, safe_log));
|
return console.log.apply(console, [].map.call(arguments, function(arg) {
|
||||||
|
return safe_log(arg, 3);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, { timeout: 5000 });
|
}, { timeout: 5000 });
|
||||||
@@ -59,7 +64,7 @@ exports.run_code = function(code) {
|
|||||||
process.stdout.write = original_write;
|
process.stdout.write = original_write;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
|
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
|
||||||
if (typeof expected != typeof actual) return false;
|
if (typeof expected != typeof actual) return false;
|
||||||
if (typeof expected != "string") {
|
if (typeof expected != "string") {
|
||||||
if (expected.name != actual.name) return false;
|
if (expected.name != actual.name) return false;
|
||||||
|
|||||||
218
test/ufuzz.js
218
test/ufuzz.js
@@ -48,8 +48,9 @@ var STMT_COUNT_FROM_GLOBAL = true; // count statement depth from nearest functio
|
|||||||
var num_iterations = +process.argv[2] || 1/0;
|
var num_iterations = +process.argv[2] || 1/0;
|
||||||
var verbose = false; // log every generated test
|
var verbose = false; // log every generated test
|
||||||
var verbose_interval = false; // log every 100 generated tests
|
var verbose_interval = false; // log every 100 generated tests
|
||||||
var verbose_error = false;
|
|
||||||
var use_strict = false;
|
var use_strict = false;
|
||||||
|
var catch_redef = require.main === module;
|
||||||
|
var generate_directive = require.main === module;
|
||||||
for (var i = 2; i < process.argv.length; ++i) {
|
for (var i = 2; i < process.argv.length; ++i) {
|
||||||
switch (process.argv[i]) {
|
switch (process.argv[i]) {
|
||||||
case '-v':
|
case '-v':
|
||||||
@@ -58,9 +59,6 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
case '-V':
|
case '-V':
|
||||||
verbose_interval = true;
|
verbose_interval = true;
|
||||||
break;
|
break;
|
||||||
case '-E':
|
|
||||||
verbose_error = true;
|
|
||||||
break;
|
|
||||||
case '-t':
|
case '-t':
|
||||||
MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i];
|
MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i];
|
||||||
if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run');
|
if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run');
|
||||||
@@ -79,6 +77,12 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
STMT_SECOND_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name];
|
STMT_SECOND_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name];
|
||||||
if (!(STMT_SECOND_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list');
|
if (!(STMT_SECOND_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list');
|
||||||
break;
|
break;
|
||||||
|
case '--no-catch-redef':
|
||||||
|
catch_redef = false;
|
||||||
|
break;
|
||||||
|
case '--no-directive':
|
||||||
|
generate_directive = false;
|
||||||
|
break;
|
||||||
case '--use-strict':
|
case '--use-strict':
|
||||||
use_strict = true;
|
use_strict = true;
|
||||||
break;
|
break;
|
||||||
@@ -103,11 +107,12 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
console.log('<number>: generate this many cases (if used must be first arg)');
|
console.log('<number>: generate this many cases (if used must be first arg)');
|
||||||
console.log('-v: print every generated test case');
|
console.log('-v: print every generated test case');
|
||||||
console.log('-V: print every 100th generated test case');
|
console.log('-V: print every 100th generated test case');
|
||||||
console.log('-E: print generated test case with runtime error');
|
|
||||||
console.log('-t <int>: generate this many toplevels per run (more take longer)');
|
console.log('-t <int>: generate this many toplevels per run (more take longer)');
|
||||||
console.log('-r <int>: maximum recursion depth for generator (higher takes longer)');
|
console.log('-r <int>: maximum recursion depth for generator (higher takes longer)');
|
||||||
console.log('-s1 <statement name>: force the first level statement to be this one (see list below)');
|
console.log('-s1 <statement name>: force the first level statement to be this one (see list below)');
|
||||||
console.log('-s2 <statement name>: force the second level statement to be this one (see list below)');
|
console.log('-s2 <statement name>: force the second level statement to be this one (see list below)');
|
||||||
|
console.log('--no-catch-redef: do not redefine catch variables');
|
||||||
|
console.log('--no-directive: do not generate directives');
|
||||||
console.log('--use-strict: generate "use strict"');
|
console.log('--use-strict: generate "use strict"');
|
||||||
console.log('--stmt-depth-from-func: reset statement depth counter at each function, counts from global otherwise');
|
console.log('--stmt-depth-from-func: reset statement depth counter at each function, counts from global otherwise');
|
||||||
console.log('--only-stmt <statement names>: a comma delimited white list of statements that may be generated');
|
console.log('--only-stmt <statement names>: a comma delimited white list of statements that may be generated');
|
||||||
@@ -192,12 +197,33 @@ var ASSIGNMENTS = [
|
|||||||
'=',
|
'=',
|
||||||
'=',
|
'=',
|
||||||
'=',
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
'=',
|
||||||
|
|
||||||
'==',
|
|
||||||
'!=',
|
|
||||||
'===',
|
|
||||||
'!==',
|
|
||||||
'+=',
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
'+=',
|
||||||
|
|
||||||
'-=',
|
'-=',
|
||||||
'*=',
|
'*=',
|
||||||
'/=',
|
'/=',
|
||||||
@@ -207,7 +233,8 @@ var ASSIGNMENTS = [
|
|||||||
'<<=',
|
'<<=',
|
||||||
'>>=',
|
'>>=',
|
||||||
'>>>=',
|
'>>>=',
|
||||||
'%=' ];
|
'%=',
|
||||||
|
];
|
||||||
|
|
||||||
var UNARY_SAFE = [
|
var UNARY_SAFE = [
|
||||||
'+',
|
'+',
|
||||||
@@ -276,6 +303,7 @@ var TYPEOF_OUTCOMES = [
|
|||||||
'symbol',
|
'symbol',
|
||||||
'crap' ];
|
'crap' ];
|
||||||
|
|
||||||
|
var unique_vars = [];
|
||||||
var loops = 0;
|
var loops = 0;
|
||||||
var funcs = 0;
|
var funcs = 0;
|
||||||
var labels = 10000;
|
var labels = 10000;
|
||||||
@@ -290,6 +318,10 @@ function strictMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createTopLevelCode() {
|
function createTopLevelCode() {
|
||||||
|
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
||||||
|
unique_vars.length = 0;
|
||||||
|
loops = 0;
|
||||||
|
funcs = 0;
|
||||||
return [
|
return [
|
||||||
strictMode(),
|
strictMode(),
|
||||||
'var a = 100, b = 10, c = 0;',
|
'var a = 100, b = 10, c = 0;',
|
||||||
@@ -325,33 +357,36 @@ function createArgs() {
|
|||||||
return args.join(', ');
|
return args.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterDirective(s) {
|
||||||
|
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ';' + s[2];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ';'; }
|
if (--recurmax < 0) { return ';'; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var func = funcs++;
|
var func = funcs++;
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
var name = (inGlobal || rng(5) > 0) ? 'f' + func : createVarName(MANDATORY, noDecl);
|
var name;
|
||||||
if (name === 'a' || name === 'b' || name === 'c') name = 'f' + func; // quick hack to prevent assignment to func names of being called
|
if (inGlobal || rng(5) > 0) name = 'f' + func;
|
||||||
var s = '';
|
else {
|
||||||
|
unique_vars.push('a', 'b', 'c');
|
||||||
|
name = createVarName(MANDATORY, noDecl);
|
||||||
|
unique_vars.length -= 3;
|
||||||
|
}
|
||||||
|
var s = [
|
||||||
|
'function ' + name + '(' + createParams() + '){',
|
||||||
|
strictMode()
|
||||||
|
];
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
s = [
|
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth));
|
||||||
'function ' + name + '(' + createParams() + '){',
|
|
||||||
strictMode(),
|
|
||||||
createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth),
|
|
||||||
'}',
|
|
||||||
''
|
|
||||||
].join('\n');
|
|
||||||
} else {
|
} else {
|
||||||
// functions with statements
|
// functions with statements
|
||||||
s = [
|
s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
||||||
'function ' + name + '(' + createParams() + '){',
|
|
||||||
strictMode(),
|
|
||||||
createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
|
||||||
'}',
|
|
||||||
''
|
|
||||||
].join('\n');
|
|
||||||
}
|
}
|
||||||
|
s.push('}', '');
|
||||||
|
s = filterDirective(s).join('\n');
|
||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
|
||||||
@@ -359,7 +394,6 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
|||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
|
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
|
||||||
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +440,7 @@ function getLabel(label) {
|
|||||||
return label && " L" + label;
|
return label && " L" + label;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, target) {
|
||||||
++stmtDepth;
|
++stmtDepth;
|
||||||
var loop = ++loops;
|
var loop = ++loops;
|
||||||
if (--recurmax < 0) {
|
if (--recurmax < 0) {
|
||||||
@@ -414,10 +448,11 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow to forcefully generate certain structures at first or second recursion level
|
// allow to forcefully generate certain structures at first or second recursion level
|
||||||
var target = 0;
|
if (target === undefined) {
|
||||||
if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE;
|
if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE;
|
||||||
else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE;
|
else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE;
|
||||||
else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)];
|
else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)];
|
||||||
|
}
|
||||||
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case STMT_BLOCK:
|
case STMT_BLOCK:
|
||||||
@@ -460,20 +495,22 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
case STMT_VAR:
|
case STMT_VAR:
|
||||||
switch (rng(3)) {
|
switch (rng(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
|
unique_vars.push('c');
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
if (name === 'c') name = 'a';
|
unique_vars.pop();
|
||||||
return 'var ' + name + ';';
|
return 'var ' + name + ';';
|
||||||
case 1:
|
case 1:
|
||||||
// initializer can only have one expression
|
// initializer can only have one expression
|
||||||
|
unique_vars.push('c');
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
if (name === 'c') name = 'b';
|
unique_vars.pop();
|
||||||
return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||||
default:
|
default:
|
||||||
// initializer can only have one expression
|
// initializer can only have one expression
|
||||||
|
unique_vars.push('c');
|
||||||
var n1 = createVarName(MANDATORY);
|
var n1 = createVarName(MANDATORY);
|
||||||
if (n1 === 'c') n1 = 'b';
|
|
||||||
var n2 = createVarName(MANDATORY);
|
var n2 = createVarName(MANDATORY);
|
||||||
if (n2 === 'c') n2 = 'b';
|
unique_vars.pop();
|
||||||
return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||||
}
|
}
|
||||||
case STMT_RETURN_ETC:
|
case STMT_RETURN_ETC:
|
||||||
@@ -514,8 +551,11 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
var catchName = createVarName(MANDATORY);
|
var catchName = createVarName(MANDATORY);
|
||||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
||||||
|
if (!catch_redef) unique_vars.push(catchName);
|
||||||
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
||||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); // remove catch name
|
// remove catch name
|
||||||
|
if (!catch_redef) unique_vars.pop();
|
||||||
|
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
||||||
}
|
}
|
||||||
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
||||||
return s;
|
return s;
|
||||||
@@ -593,8 +633,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
unique_vars.push('c');
|
||||||
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
||||||
if (name == 'c') name = 'a';
|
unique_vars.pop();
|
||||||
var s = [];
|
var s = [];
|
||||||
switch (rng(5)) {
|
switch (rng(5)) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -636,7 +677,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
strictMode()
|
strictMode()
|
||||||
);
|
);
|
||||||
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
||||||
if (rng(2)) s.push('this.' + getDotKey() + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
|
if (rng(2)) s.push('this.' + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
|
||||||
else s.push('this[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']' + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
|
else s.push('this[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']' + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
|
||||||
}
|
}
|
||||||
s.push(
|
s.push(
|
||||||
@@ -646,7 +687,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
return s.join('\n');
|
return filterDirective(s).join('\n');
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return createTypeofExpr(recurmax, stmtDepth, canThrow);
|
return createTypeofExpr(recurmax, stmtDepth, canThrow);
|
||||||
@@ -689,19 +730,19 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
") || " + rng(10) + ").toString()[" +
|
") || " + rng(10) + ").toString()[" +
|
||||||
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] ";
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] ";
|
||||||
case p++:
|
case p++:
|
||||||
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createArrayLiteral(recurmax, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createObjectLiteral(recurmax, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '[' +
|
return createArrayLiteral(recurmax, stmtDepth, canThrow) + '[' +
|
||||||
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
||||||
case p++:
|
case p++:
|
||||||
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '[' +
|
return createObjectLiteral(recurmax, stmtDepth, canThrow) + '[' +
|
||||||
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
||||||
case p++:
|
case p++:
|
||||||
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '.' + getDotKey();
|
return createArrayLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey();
|
||||||
case p++:
|
case p++:
|
||||||
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '.' + getDotKey();
|
return createObjectLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey();
|
||||||
case p++:
|
case p++:
|
||||||
var name = getVarName();
|
var name = getVarName();
|
||||||
return name + ' && ' + name + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
return name + ' && ' + name + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
|
||||||
@@ -713,7 +754,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
return _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArrayLiteral(recurmax, noComma, stmtDepth, canThrow) {
|
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
recurmax--;
|
||||||
var arr = "[";
|
var arr = "[";
|
||||||
for (var i = rng(6); --i >= 0;) {
|
for (var i = rng(6); --i >= 0;) {
|
||||||
@@ -746,18 +787,56 @@ var KEYS = [
|
|||||||
"3",
|
"3",
|
||||||
].concat(SAFE_KEYS);
|
].concat(SAFE_KEYS);
|
||||||
|
|
||||||
function getDotKey() {
|
function getDotKey(assign) {
|
||||||
return SAFE_KEYS[rng(SAFE_KEYS.length)];
|
var key;
|
||||||
|
do {
|
||||||
|
key = SAFE_KEYS[rng(SAFE_KEYS.length)];
|
||||||
|
} while (assign && key == "length");
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createObjectLiteral(recurmax, noComma, stmtDepth, canThrow) {
|
function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
var obj = "({";
|
var s;
|
||||||
for (var i = rng(6); --i >= 0;) {
|
var prop1 = getDotKey();
|
||||||
var key = KEYS[rng(KEYS.length)];
|
if (rng(2) == 0) {
|
||||||
obj += key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "), ";
|
s = [
|
||||||
|
'get ' + prop1 + '(){',
|
||||||
|
strictMode(),
|
||||||
|
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||||
|
'},'
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
var prop2;
|
||||||
|
do {
|
||||||
|
prop2 = getDotKey();
|
||||||
|
} while (prop1 == prop2);
|
||||||
|
s = [
|
||||||
|
'set ' + prop1 + '(' + createVarName(MANDATORY) + '){',
|
||||||
|
strictMode(),
|
||||||
|
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
'this.' + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ';',
|
||||||
|
'},'
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return obj + "})";
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
return filterDirective(s).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
|
recurmax--;
|
||||||
|
var obj = ['({'];
|
||||||
|
for (var i = rng(6); --i >= 0;) {
|
||||||
|
if (rng(20) == 0) {
|
||||||
|
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
|
||||||
|
} else {
|
||||||
|
var key = KEYS[rng(KEYS.length)];
|
||||||
|
obj.push(key + ':(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + '),');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.push('})');
|
||||||
|
return obj.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||||
@@ -787,7 +866,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
|
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
|
||||||
case 4:
|
case 4:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
expr = '(' + assignee + '.' + getDotKey() + createAssignment()
|
expr = '(' + assignee + '.' + getDotKey(true) + createAssignment()
|
||||||
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')';
|
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')';
|
||||||
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
|
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
|
||||||
default:
|
default:
|
||||||
@@ -844,17 +923,24 @@ function getVarName() {
|
|||||||
|
|
||||||
function createVarName(maybe, dontStore) {
|
function createVarName(maybe, dontStore) {
|
||||||
if (!maybe || rng(2)) {
|
if (!maybe || rng(2)) {
|
||||||
var name = VAR_NAMES[rng(VAR_NAMES.length)];
|
|
||||||
var suffix = rng(3);
|
var suffix = rng(3);
|
||||||
if (suffix) {
|
var name;
|
||||||
name += '_' + suffix;
|
do {
|
||||||
if (!dontStore) VAR_NAMES.push(name);
|
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||||
}
|
if (suffix) name += '_' + suffix;
|
||||||
|
} while (unique_vars.indexOf(name) >= 0);
|
||||||
|
if (suffix && !dontStore) VAR_NAMES.push(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (require.main !== module) {
|
||||||
|
exports.createTopLevelCode = createTopLevelCode;
|
||||||
|
exports.num_iterations = num_iterations;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function try_beautify(code, result) {
|
function try_beautify(code, result) {
|
||||||
var beautified = UglifyJS.minify(code, {
|
var beautified = UglifyJS.minify(code, {
|
||||||
compress: false,
|
compress: false,
|
||||||
@@ -973,10 +1059,6 @@ var uglify_code, uglify_result, ok;
|
|||||||
for (var round = 1; round <= num_iterations; round++) {
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
|
|
||||||
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
|
||||||
loops = 0;
|
|
||||||
funcs = 0;
|
|
||||||
|
|
||||||
original_code = createTopLevelCode();
|
original_code = createTopLevelCode();
|
||||||
original_result = sandbox.run_code(original_code);
|
original_result = sandbox.run_code(original_code);
|
||||||
(typeof original_result != "string" ? fallback_options : minify_options).forEach(function(options) {
|
(typeof original_result != "string" ? fallback_options : minify_options).forEach(function(options) {
|
||||||
@@ -992,7 +1074,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||||
else if (verbose_error && typeof original_result != "string") {
|
else if (typeof original_result != "string") {
|
||||||
console.log("//=============================================================");
|
console.log("//=============================================================");
|
||||||
console.log("// original code");
|
console.log("// original code");
|
||||||
try_beautify(original_code, original_result);
|
try_beautify(original_code, original_result);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
exports["Dictionary"] = Dictionary;
|
exports["Dictionary"] = Dictionary;
|
||||||
exports["TreeWalker"] = TreeWalker;
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["_push_uniq"] = push_uniq;
|
exports["_push_uniq"] = push_uniq;
|
||||||
|
|||||||
Reference in New Issue
Block a user