Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c84dfa151 | ||
|
|
5359900b78 | ||
|
|
739fa266f8 | ||
|
|
da24dfb59e | ||
|
|
a2f27c7640 | ||
|
|
3c556b8689 | ||
|
|
7110c6923b | ||
|
|
b27b6807cb | ||
|
|
ba6e29d6fd | ||
|
|
d4685640a0 | ||
|
|
ac7b5c07d7 | ||
|
|
0cd4a199b0 | ||
|
|
35435d4bd3 | ||
|
|
d0bb147639 | ||
|
|
4723b4541e | ||
|
|
9d23ba0a22 | ||
|
|
a08d42555a | ||
|
|
fd7ad8e779 | ||
|
|
a36c5472d2 | ||
|
|
8bfd891c09 | ||
|
|
ef9f7ca3e7 | ||
|
|
acc443b2cf | ||
|
|
f87e7be12c | ||
|
|
c0614654d9 | ||
|
|
0358637725 | ||
|
|
63b5b6d2b3 | ||
|
|
e675262d51 | ||
|
|
c1e771a89a | ||
|
|
bc7a88baea | ||
|
|
018e0350f8 | ||
|
|
d37ee4d41c | ||
|
|
7793c6c389 | ||
|
|
90ec468240 | ||
|
|
994293e972 | ||
|
|
b57bae4b9e | ||
|
|
e23a10f7f9 | ||
|
|
884ec4e8a5 | ||
|
|
e616916de5 | ||
|
|
8d21516623 | ||
|
|
74368c3dba | ||
|
|
18dbceb36f | ||
|
|
65d39a3702 | ||
|
|
24917e7084 | ||
|
|
e84957e3da | ||
|
|
c11a748908 | ||
|
|
90017051f2 | ||
|
|
fc816628c1 | ||
|
|
46ad273df4 | ||
|
|
b689028e87 | ||
|
|
1e831df1f6 | ||
|
|
c12486bab4 | ||
|
|
52e94a0723 | ||
|
|
16b97f9558 | ||
|
|
dbfa5d4d14 | ||
|
|
ba54d074d8 | ||
|
|
0818d396c5 | ||
|
|
770f3ba5fe | ||
|
|
553034fe52 | ||
|
|
7fe8c9150a | ||
|
|
6c419bc083 | ||
|
|
25321df959 | ||
|
|
cf1b0165af | ||
|
|
c3d358a5b8 | ||
|
|
68497d0258 | ||
|
|
71c3d04681 | ||
|
|
4c89550c43 | ||
|
|
7ebfb22d16 | ||
|
|
6eceac0966 | ||
|
|
fc5aee662d | ||
|
|
5fbbb43839 | ||
|
|
df2cfcb5fc | ||
|
|
623a0d920f | ||
|
|
e8c04f8cb6 | ||
|
|
110c1ac097 | ||
|
|
15ef272790 | ||
|
|
b3a706114c | ||
|
|
cc2d7acaf0 | ||
|
|
dfb86ccdd1 | ||
|
|
0417a69c3e | ||
|
|
2dbafbb4ee | ||
|
|
311c074622 | ||
|
|
a10c7793bb | ||
|
|
0b7d65d331 | ||
|
|
8b954b022b | ||
|
|
0013cbf91f | ||
|
|
1956edd503 | ||
|
|
560ccc1221 | ||
|
|
10a71c182b | ||
|
|
ddc0ed7072 | ||
|
|
c00efe56f4 | ||
|
|
28bcdbd7df | ||
|
|
6a8aed2049 | ||
|
|
a8785fb694 | ||
|
|
dd6d7b3d88 | ||
|
|
94f3819dc6 | ||
|
|
be1f5199f4 | ||
|
|
95aea0e33c | ||
|
|
a1b2735dd8 | ||
|
|
f345175bc2 | ||
|
|
bb45f48ab7 | ||
|
|
b2f27fd873 | ||
|
|
ced32f9bd8 | ||
|
|
dfc3ec9cef | ||
|
|
1896694532 | ||
|
|
5f269cd573 | ||
|
|
6988cd9558 | ||
|
|
2390fae5c4 | ||
|
|
56fce2131c | ||
|
|
7e575e9d7f | ||
|
|
cb4a02949e | ||
|
|
f85a206b9e |
25
.github/ISSUE_TEMPLATE.md
vendored
25
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,25 +0,0 @@
|
||||
**Bug report or feature request?**
|
||||
|
||||
<!-- Note: sub-optimal but correct code is not a bug -->
|
||||
|
||||
**Uglify version (`uglifyjs -V`)**
|
||||
|
||||
**JavaScript input**
|
||||
|
||||
<!--
|
||||
A complete parsable JS program exhibiting the issue with
|
||||
UglifyJS alone - without third party tools or libraries.
|
||||
Ideally the input should be as small as possible.
|
||||
Post a link to a gist if necessary.
|
||||
|
||||
Issues without a reproducible test case will be closed.
|
||||
-->
|
||||
|
||||
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
||||
|
||||
**JavaScript output or error produced.**
|
||||
|
||||
<!--
|
||||
Note: `uglify-js` only supports JavaScript.
|
||||
Those wishing to minify ES6+ should transpile first.
|
||||
-->
|
||||
51
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Note: sub-optimal but correct code is not a bug -->
|
||||
|
||||
**Uglify version (`uglifyjs -V`)**
|
||||
|
||||
**JavaScript input**
|
||||
|
||||
<!--
|
||||
A complete parsable JS program exhibiting the issue with UglifyJS alone
|
||||
- without third party tools or libraries.
|
||||
|
||||
Ideally the input should be as small as possible, but may be large if isolating
|
||||
the problem proves to be difficult. The most important thing is that the
|
||||
standalone program reliably exhibits the bug when minified. Provide a link to a
|
||||
gist if necessary.
|
||||
|
||||
Solely providing minified output without the original uglify JS input is not
|
||||
useful in determining the cause of the problem. Issues without a reproducible
|
||||
test case will be closed.
|
||||
-->
|
||||
|
||||
**The `uglifyjs` CLI command executed or `minify()` options used.**
|
||||
|
||||
<!--
|
||||
Command-line or API call to UglifyJS without third party tools or libraries.
|
||||
|
||||
For users using bundlers or transpilers, you may be able to gather the required
|
||||
information through setting the `UGLIFY_BUG_REPORT` environment variable:
|
||||
|
||||
export UGLIFY_BUG_REPORT=1 (bash)
|
||||
set UGLIFY_BUG_REPORT=1 (Command Prompt)
|
||||
$Env:UGLIFY_BUG_REPORT=1 (PowerShell)
|
||||
|
||||
before running your usual build process. The resulting "minified" output should
|
||||
contain the necessary details for this report.
|
||||
-->
|
||||
|
||||
**JavaScript output or error produced.**
|
||||
|
||||
<!--
|
||||
Only minified code that produces different output (or error) from the original
|
||||
upon execution would be considered a bug.
|
||||
-->
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -7,13 +7,13 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
node: [ "0.8", "0.10", "0.12", "4", "6", "8", "10", "12", latest ]
|
||||
node: [ '0.8', '0.10', '0.12', '4', '6', '8', '10', '12', latest ]
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
script: [ compress, mocha, release/benchmark, release/jetstream ]
|
||||
exclude:
|
||||
- node: "0.8"
|
||||
- node: '0.8'
|
||||
script: release/benchmark
|
||||
- node: "0.8"
|
||||
- node: '0.8'
|
||||
script: release/jetstream
|
||||
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
- name: Perform tests
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
|
||||
cd ~/.nvs
|
||||
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
|
||||
|
||||
31
.github/workflows/ufuzz.yml
vendored
31
.github/workflows/ufuzz.yml
vendored
@@ -2,7 +2,7 @@ name: Fuzzing
|
||||
on:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "*/5 * * * *"
|
||||
- cron: '*/5 * * * *'
|
||||
env:
|
||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||
CAUSE: ${{ github.event_name }}
|
||||
@@ -13,22 +13,41 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
name: ${{ matrix.os }}
|
||||
include:
|
||||
- node: latest
|
||||
os: macos-latest
|
||||
- node: '8'
|
||||
os: ubuntu-latest
|
||||
- node: '8'
|
||||
os: ubuntu-latest
|
||||
- node: '8'
|
||||
os: windows-latest
|
||||
- node: '8'
|
||||
os: windows-latest
|
||||
name: ${{ matrix.node }} ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
NODE: ${{ matrix.node }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install GNU Core Utilities
|
||||
if: ${{ startsWith(matrix.os, 'macos') }}
|
||||
env:
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
shell: bash
|
||||
run: |
|
||||
brew install coreutils
|
||||
- name: Perform fuzzing
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 8 && nvs use 8'; do
|
||||
git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
|
||||
cd ~/.nvs
|
||||
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
|
||||
cd -
|
||||
done
|
||||
. ~/.nvs/nvs.sh --version
|
||||
nvs use 8
|
||||
nvs use $NODE
|
||||
node --version
|
||||
npm config set audit false
|
||||
npm config set optional false
|
||||
|
||||
89
README.md
89
README.md
@@ -135,6 +135,10 @@ a double dash to prevent input files being used as option arguments:
|
||||
`//# sourceMappingURL`.
|
||||
--timings Display operations run time on STDERR.
|
||||
--toplevel Compress and/or mangle variables in top level scope.
|
||||
--v8 Support non-standard Chrome & Node.js
|
||||
Equivalent to setting `v8: true` in `minify()`
|
||||
for `mangle` and `output` options.
|
||||
By default UglifyJS will not try to be v8-proof.
|
||||
--verbose Print diagnostic messages.
|
||||
--warn Print warning messages.
|
||||
--webkit Support non-standard Safari/Webkit.
|
||||
@@ -522,6 +526,8 @@ if (result.error) throw result.error;
|
||||
- `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.
|
||||
|
||||
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs.
|
||||
|
||||
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||
|
||||
@@ -621,7 +627,11 @@ to be `false` and all symbol names will be omitted.
|
||||
- `arguments` (default: `true`) -- replace `arguments[index]` with function
|
||||
parameter name whenever possible.
|
||||
|
||||
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
|
||||
- `arrows` (default: `true`) -- apply optimizations to arrow functions
|
||||
|
||||
- `assignments` (default: `true`) -- apply optimizations to assignment expressions
|
||||
|
||||
- `awaits` (default: `true`) -- apply optimizations to `await` expressions
|
||||
|
||||
- `booleans` (default: `true`) -- various optimizations for boolean context,
|
||||
for example `!!a ? b : c → a ? b : c`
|
||||
@@ -638,6 +648,8 @@ to be `false` and all symbol names will be omitted.
|
||||
|
||||
- `dead_code` (default: `true`) -- remove unreachable code
|
||||
|
||||
- `default_values` (default: `true`) -- drop overshadowed default values
|
||||
|
||||
- `directives` (default: `true`) -- remove redundant or non-standard directives
|
||||
|
||||
- `drop_console` (default: `false`) -- Pass `true` to discard calls to
|
||||
@@ -683,13 +695,9 @@ to be `false` and all symbol names will be omitted.
|
||||
|
||||
- `join_vars` (default: `true`) -- join consecutive `var` statements
|
||||
|
||||
- `keep_fargs` (default: `strict`) -- Discard unused function arguments. Code
|
||||
which relies on `Function.length` will break if this is done indiscriminately,
|
||||
i.e. when passing `true`. Pass `false` to always retain function arguments.
|
||||
|
||||
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
|
||||
compressor from discarding function names. Useful for code relying on
|
||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle-options).
|
||||
- `keep_fargs` (default: `false`) -- discard unused function arguments except
|
||||
when unsafe to do so, e.g. code which relies on `Function.prototype.length`.
|
||||
Pass `true` to always retain function arguments.
|
||||
|
||||
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
|
||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||
@@ -739,6 +747,8 @@ to be `false` and all symbol names will be omitted.
|
||||
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
|
||||
used as constant values.
|
||||
|
||||
- `rests` (default: `true`) -- apply optimizations to rest parameters
|
||||
|
||||
- `sequences` (default: `true`) -- join consecutive simple statements using the
|
||||
comma operator. May be set to a positive integer to specify the maximum number
|
||||
of consecutive comma sequences that will be generated. If this option is set to
|
||||
@@ -753,20 +763,23 @@ to be `false` and all symbol names will be omitted.
|
||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||
example: `/*@__PURE__*/foo();`
|
||||
|
||||
- `spread` (default: `true`) -- flatten spread expressions.
|
||||
- `spreads` (default: `true`) -- flatten spread expressions.
|
||||
|
||||
- `strings` (default: `true`) -- compact string concatenations.
|
||||
|
||||
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||
|
||||
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
|
||||
variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
|
||||
both unreferenced functions and variables)
|
||||
- `templates` (default: `true`) -- compact template literals by embedding expressions
|
||||
and/or converting to string literals, e.g. `` `foo ${42}` → "foo 42"``
|
||||
|
||||
- `top_retain` (default: `null`) -- prevent specific toplevel functions and
|
||||
variables from `unused` removal (can be array, comma-separated, RegExp or
|
||||
function. Implies `toplevel`)
|
||||
|
||||
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
|
||||
variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
|
||||
both unreferenced functions and variables)
|
||||
|
||||
- `typeofs` (default: `true`) -- Transforms `typeof foo == "undefined"` into
|
||||
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||
earlier versions due to known issues.
|
||||
@@ -803,10 +816,6 @@ to be `false` and all symbol names will be omitted.
|
||||
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
|
||||
where `eval` or `with` are used.
|
||||
|
||||
- `keep_fnames` (default `false`) -- Pass `true` to not mangle function names.
|
||||
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
|
||||
[compress option](#compress-options).
|
||||
|
||||
- `reserved` (default `[]`) -- Pass an array of identifiers that should be
|
||||
excluded from mangling. Example: `["foo", "bar"]`.
|
||||
|
||||
@@ -873,7 +882,7 @@ can pass additional arguments that control the code output:
|
||||
comments, `"some"` to preserve multi-line comments that contain `@cc_on`,
|
||||
`@license`, or `@preserve` (case-insensitive), a regular expression string
|
||||
(e.g. `/^!/`), or a function which returns `boolean`, e.g.
|
||||
```js
|
||||
```javascript
|
||||
function(node, comment) {
|
||||
return comment.value.indexOf("@type " + node.TYPE) >= 0;
|
||||
}
|
||||
@@ -919,8 +928,6 @@ can pass additional arguments that control the code output:
|
||||
|
||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||
|
||||
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
|
||||
|
||||
- `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).
|
||||
@@ -1146,7 +1153,7 @@ To enable fast minify mode from the CLI use:
|
||||
uglifyjs file.js -m
|
||||
```
|
||||
To enable fast minify mode with the API use:
|
||||
```js
|
||||
```javascript
|
||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||
```
|
||||
|
||||
@@ -1178,10 +1185,10 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
||||
`Object.preventExtensions()` or `Object.seal()`).
|
||||
- Earlier versions of JavaScript will throw `SyntaxError` with the following:
|
||||
```js
|
||||
```javascript
|
||||
({
|
||||
p: 42,
|
||||
get p() {},
|
||||
p: 42,
|
||||
get p() {},
|
||||
});
|
||||
// SyntaxError: Object literal may not have data and accessor property with
|
||||
// the same name
|
||||
@@ -1191,7 +1198,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
versions of Chrome and Node.js may be altered.
|
||||
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped
|
||||
within `function(){ ... }`, thus forbids aliasing of declared global variables:
|
||||
```js
|
||||
```javascript
|
||||
A = "FAIL";
|
||||
var B = "FAIL";
|
||||
// can be `global`, `self`, `window` etc.
|
||||
@@ -1211,7 +1218,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
suppress those errors.
|
||||
- Earlier versions of Chrome and Node.js will throw `ReferenceError` with the
|
||||
following:
|
||||
```js
|
||||
```javascript
|
||||
var a;
|
||||
try {
|
||||
throw 42;
|
||||
@@ -1224,20 +1231,42 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
||||
```js
|
||||
```javascript
|
||||
a => {
|
||||
let a;
|
||||
let a;
|
||||
};
|
||||
// SyntaxError: Identifier 'a' has already been declared
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Later versions of JavaScript will throw `SyntaxError` with the following:
|
||||
```js
|
||||
```javascript
|
||||
try {
|
||||
// ...
|
||||
// ...
|
||||
} catch ({ message: a }) {
|
||||
var a;
|
||||
var a;
|
||||
}
|
||||
// SyntaxError: Identifier 'a' has already been declared
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Some versions of Chrome and Node.js will throw `ReferenceError` with the
|
||||
following:
|
||||
```javascript
|
||||
console.log(((a, b = function() {
|
||||
return a;
|
||||
// ReferenceError: a is not defined
|
||||
}()) => b)());
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Some arithmetic operations with `BigInt` may throw `TypeError`:
|
||||
```javascript
|
||||
1n + 1;
|
||||
// TypeError: can't convert BigInt to number
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Some versions of JavaScript will throw `SyntaxError` with the
|
||||
following:
|
||||
```javascript
|
||||
console.log(String.raw`\uFo`);
|
||||
// SyntaxError: Invalid Unicode escape sequence
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
require("../tools/exit");
|
||||
require("../tools/tty");
|
||||
|
||||
var fs = require("fs");
|
||||
var info = require("../package.json");
|
||||
@@ -265,7 +265,7 @@ if (paths.length) {
|
||||
process.stdin.on("data", function(chunk) {
|
||||
chunks.push(chunk);
|
||||
}).on("end", function() {
|
||||
files = [ chunks.join("") ];
|
||||
files = { STDIN: chunks.join("") };
|
||||
run();
|
||||
});
|
||||
process.stdin.resume();
|
||||
|
||||
200
lib/ast.js
200
lib/ast.js
@@ -160,6 +160,8 @@ var restore_transforms = [];
|
||||
AST_Node.enable_validation = function() {
|
||||
AST_Node.disable_validation();
|
||||
(function validate_transform(ctor) {
|
||||
ctor.SUBCLASSES.forEach(validate_transform);
|
||||
if (!HOP(ctor.prototype, "transform")) return;
|
||||
var transform = ctor.prototype.transform;
|
||||
ctor.prototype.transform = function(tw, in_list) {
|
||||
var node = transform.call(this, tw, in_list);
|
||||
@@ -173,7 +175,6 @@ AST_Node.enable_validation = function() {
|
||||
restore_transforms.push(function() {
|
||||
ctor.prototype.transform = transform;
|
||||
});
|
||||
ctor.SUBCLASSES.forEach(validate_transform);
|
||||
})(this);
|
||||
};
|
||||
|
||||
@@ -207,13 +208,23 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
||||
$documentation: "The empty statement (empty block or simply a semicolon)"
|
||||
}, AST_Statement);
|
||||
|
||||
function must_be_expression(node, prop) {
|
||||
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
||||
if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
||||
if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
||||
if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
|
||||
throw new Error(prop + " cannot be AST_Statement");
|
||||
function validate_expression(value, prop, multiple, allow_spread, allow_hole) {
|
||||
multiple = multiple ? "contain" : "be";
|
||||
if (!(value instanceof AST_Node)) throw new Error(prop + " must " + multiple + " AST_Node");
|
||||
if (value instanceof AST_DefaultValue) throw new Error(prop + " cannot " + multiple + " AST_DefaultValue");
|
||||
if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
|
||||
if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
|
||||
if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
|
||||
if (value instanceof AST_Statement && !is_function(value)) {
|
||||
throw new Error(prop + " cannot " + multiple + " AST_Statement");
|
||||
}
|
||||
if (value instanceof AST_SymbolDeclaration) {
|
||||
throw new Error(prop + " cannot " + multiple + " AST_SymbolDeclaration");
|
||||
}
|
||||
}
|
||||
|
||||
function must_be_expression(node, prop) {
|
||||
validate_expression(node[prop], prop);
|
||||
}
|
||||
|
||||
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||
@@ -238,7 +249,7 @@ var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_s
|
||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||
variables: "[Object/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
|
||||
},
|
||||
clone: function(deep) {
|
||||
var node = this._clone(deep);
|
||||
@@ -461,7 +472,7 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
|
||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
$documentation: "The toplevel scope",
|
||||
$propdoc: {
|
||||
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
|
||||
globals: "[Object/S] a map of name ---> SymbolDef for all undeclared names",
|
||||
},
|
||||
wrap: function(name) {
|
||||
var body = this.body;
|
||||
@@ -502,14 +513,19 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
}
|
||||
}, AST_Scope);
|
||||
|
||||
var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
||||
var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", {
|
||||
$documentation: "Base class for functions",
|
||||
$propdoc: {
|
||||
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||
argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||
rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent",
|
||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
||||
},
|
||||
each_argname: function(visit) {
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_DefaultValue) {
|
||||
node.name.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_DestructuredKeyVal) {
|
||||
node.value.walk(tw);
|
||||
return true;
|
||||
@@ -519,6 +535,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
||||
this.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
if (this.rest) this.rest.walk(tw);
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
@@ -527,6 +544,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(visitor);
|
||||
});
|
||||
if (node.rest) node.rest.walk(visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
},
|
||||
@@ -534,7 +552,10 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
||||
this.argnames.forEach(function(node) {
|
||||
validate_destructured(node, function(node) {
|
||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
if (this.rest != null) validate_destructured(this.rest, function(node) {
|
||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("rest must be AST_SymbolFunarg");
|
||||
});
|
||||
},
|
||||
}, AST_Scope);
|
||||
@@ -546,8 +567,20 @@ var AST_Accessor = DEFNODE("Accessor", null, {
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
function is_arrow(node) {
|
||||
return node instanceof AST_AsyncArrow || node instanceof AST_Arrow;
|
||||
}
|
||||
|
||||
function is_function(node) {
|
||||
return node instanceof AST_Arrow || node instanceof AST_AsyncFunction || node instanceof AST_Function;
|
||||
return is_arrow(node) || node instanceof AST_AsyncFunction || node instanceof AST_Function;
|
||||
}
|
||||
|
||||
function walk_lambda(node, tw) {
|
||||
if (is_arrow(node) && node.value) {
|
||||
node.value.walk(tw);
|
||||
} else {
|
||||
walk_body(node, tw);
|
||||
}
|
||||
}
|
||||
|
||||
var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
||||
@@ -561,6 +594,7 @@ var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(visitor);
|
||||
});
|
||||
if (node.rest) node.rest.walk(visitor);
|
||||
if (node.value) {
|
||||
node.value.walk(visitor);
|
||||
} else {
|
||||
@@ -579,9 +613,38 @@ var AST_Arrow = DEFNODE("Arrow", "inlined value", {
|
||||
}, AST_Lambda);
|
||||
|
||||
function is_async(node) {
|
||||
return node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
|
||||
return node instanceof AST_AsyncArrow || node instanceof AST_AsyncDefun || node instanceof AST_AsyncFunction;
|
||||
}
|
||||
|
||||
var AST_AsyncArrow = DEFNODE("AsyncArrow", "inlined value", {
|
||||
$documentation: "An asynchronous arrow function expression",
|
||||
$propdoc: {
|
||||
value: "[AST_Node?] simple return expression, or null if using function body.",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(visitor);
|
||||
});
|
||||
if (node.rest) node.rest.walk(visitor);
|
||||
if (node.value) {
|
||||
node.value.walk(visitor);
|
||||
} else {
|
||||
walk_body(node, visitor);
|
||||
}
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.name != null) throw new Error("name must be null");
|
||||
if (this.uses_arguments) throw new Error("uses_arguments must be false");
|
||||
if (this.value != null) {
|
||||
must_be_expression(this, "value");
|
||||
if (this.body.length) throw new Error("body must be empty if value exists");
|
||||
}
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined name", {
|
||||
$documentation: "An asynchronous function expression",
|
||||
$propdoc: {
|
||||
@@ -838,7 +901,6 @@ var AST_Const = DEFNODE("Const", null, {
|
||||
validate_destructured(node.name, function(node) {
|
||||
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||
});
|
||||
if (node.value != null) must_be_expression(node, "value");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
@@ -851,7 +913,6 @@ var AST_Let = DEFNODE("Let", null, {
|
||||
validate_destructured(node.name, function(node) {
|
||||
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
||||
});
|
||||
if (node.value != null) must_be_expression(node, "value");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
@@ -864,7 +925,6 @@ var AST_Var = DEFNODE("Var", null, {
|
||||
validate_destructured(node.name, function(node) {
|
||||
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||
});
|
||||
if (node.value != null) must_be_expression(node, "value");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
@@ -873,7 +933,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
||||
$propdoc: {
|
||||
name: "[AST_Destructured|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) {
|
||||
var node = this;
|
||||
@@ -882,18 +942,34 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||
if (node.value) node.value.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.value != null) must_be_expression(this, "value");
|
||||
},
|
||||
});
|
||||
|
||||
/* -----[ OTHER ]----- */
|
||||
|
||||
var AST_DefaultValue = DEFNODE("DefaultValue", "name value", {
|
||||
$documentation: "A default value declaration",
|
||||
$propdoc: {
|
||||
name: "[AST_Destructured|AST_SymbolDeclaration] name of the variable",
|
||||
value: "[AST_Node] value to assign if variable is `undefined`",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.name.walk(visitor);
|
||||
node.value.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "value");
|
||||
},
|
||||
});
|
||||
|
||||
function must_be_expressions(node, prop, allow_spread, allow_hole) {
|
||||
node[prop].forEach(function(node) {
|
||||
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
|
||||
if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
||||
if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
||||
if (node instanceof AST_Statement && !is_function(node)) {
|
||||
throw new Error(prop + " cannot contain AST_Statement");
|
||||
}
|
||||
validate_expression(node, prop, true, allow_spread, allow_hole);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1048,7 +1124,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "left");
|
||||
if (!(this instanceof AST_Assign)) must_be_expression(this, "left");
|
||||
if (typeof this.operator != "string") throw new Error("operator must be string");
|
||||
must_be_expression(this, "right");
|
||||
},
|
||||
@@ -1127,24 +1203,31 @@ var AST_Array = DEFNODE("Array", "elements", {
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Destructured = DEFNODE("Destructured", null, {
|
||||
var AST_Destructured = DEFNODE("Destructured", "rest", {
|
||||
$documentation: "Base class for destructured literal",
|
||||
$propdoc: {
|
||||
rest: "[(AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef)?] rest parameter, or null if absent",
|
||||
},
|
||||
});
|
||||
|
||||
function validate_destructured(node, check) {
|
||||
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
||||
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
|
||||
});
|
||||
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
||||
validate_destructured(prop.value, check);
|
||||
});
|
||||
function validate_destructured(node, check, allow_default) {
|
||||
if (node instanceof AST_DefaultValue && allow_default) return validate_destructured(node.name, check);
|
||||
if (node instanceof AST_Destructured) {
|
||||
if (node.rest != null) validate_destructured(node.rest, check);
|
||||
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
||||
if (!(node instanceof AST_Hole)) validate_destructured(node, check, true);
|
||||
});
|
||||
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
||||
validate_destructured(prop.value, check, true);
|
||||
});
|
||||
}
|
||||
check(node);
|
||||
}
|
||||
|
||||
var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
|
||||
$documentation: "A destructured array literal",
|
||||
$propdoc: {
|
||||
elements: "[AST_Node*] array of elements",
|
||||
elements: "[(AST_DefaultValue|AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef)*] array of elements",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
@@ -1152,6 +1235,7 @@ var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
|
||||
node.elements.forEach(function(element) {
|
||||
element.walk(visitor);
|
||||
});
|
||||
if (node.rest) node.rest.walk(visitor);
|
||||
});
|
||||
},
|
||||
}, AST_Destructured);
|
||||
@@ -1160,7 +1244,7 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
|
||||
$documentation: "A key: value destructured property",
|
||||
$propdoc: {
|
||||
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||
value: "[AST_Node] property value",
|
||||
value: "[AST_DefaultValue|AST_Destructured|AST_SymbolDeclaration|AST_SymbolRef] property value",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
@@ -1174,7 +1258,7 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
|
||||
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||
must_be_expression(this, "key");
|
||||
}
|
||||
must_be_expression(this, "value");
|
||||
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1189,6 +1273,7 @@ var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
|
||||
node.properties.forEach(function(prop) {
|
||||
prop.walk(visitor);
|
||||
});
|
||||
if (node.rest) node.rest.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
@@ -1318,7 +1403,7 @@ var AST_Label = DEFNODE("Label", "references", {
|
||||
}
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg", {
|
||||
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
|
||||
$documentation: "Reference to some symbol (not definition/declaration)",
|
||||
}, AST_Symbol);
|
||||
|
||||
@@ -1333,6 +1418,34 @@ var AST_This = DEFNODE("This", null, {
|
||||
},
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_Template = DEFNODE("Template", "expressions strings tag", {
|
||||
$documentation: "A template literal, i.e. tag`str1${expr1}...strN${exprN}strN+1`",
|
||||
$propdoc: {
|
||||
expressions: "[AST_Node*] the placeholder expressions",
|
||||
strings: "[string*] the raw text segments",
|
||||
tag: "[AST_Node] tag function, or null if absent",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.tag) node.tag.walk(visitor);
|
||||
node.expressions.forEach(function(expr) {
|
||||
expr.walk(visitor);
|
||||
});
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.expressions.length + 1 != this.strings.length) {
|
||||
throw new Error("malformed template with " + this.expressions.length + " placeholder(s) but " + this.strings.length + " text segment(s)");
|
||||
}
|
||||
must_be_expressions(this, "expressions");
|
||||
this.strings.forEach(function(string) {
|
||||
if (typeof string != "string") throw new Error("strings must contain string");
|
||||
});
|
||||
if (this.tag != null) must_be_expression(this, "tag");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Constant = DEFNODE("Constant", null, {
|
||||
$documentation: "Base class for all constants",
|
||||
});
|
||||
@@ -1355,6 +1468,19 @@ var AST_Number = DEFNODE("Number", "value", {
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.value != "number") throw new Error("value must be number");
|
||||
if (!isFinite(this.value)) throw new Error("value must be finite");
|
||||
if (this.value < 0) throw new Error("value cannot be negative");
|
||||
},
|
||||
}, AST_Constant);
|
||||
|
||||
var AST_BigInt = DEFNODE("BigInt", "value", {
|
||||
$documentation: "A BigInt literal",
|
||||
$propdoc: {
|
||||
value: "[string] the numeric representation",
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.value != "string") throw new Error("value must be string");
|
||||
if (this.value[0] == "-") throw new Error("value cannot be negative");
|
||||
},
|
||||
}, AST_Constant);
|
||||
|
||||
|
||||
1982
lib/compress.js
1982
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -87,6 +87,7 @@ function minify(files, options) {
|
||||
sourceMap: false,
|
||||
timings: false,
|
||||
toplevel: false,
|
||||
v8: false,
|
||||
validate: false,
|
||||
warnings: false,
|
||||
webkit: false,
|
||||
@@ -102,6 +103,7 @@ function minify(files, options) {
|
||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("v8", options, [ "mangle", "output" ]);
|
||||
set_shorthand("webkit", options, [ "mangle", "output" ]);
|
||||
var quoted_props;
|
||||
if (options.mangle) {
|
||||
@@ -113,6 +115,7 @@ function minify(files, options) {
|
||||
properties: false,
|
||||
reserved: [],
|
||||
toplevel: false,
|
||||
v8: false,
|
||||
webkit: false,
|
||||
}, true);
|
||||
if (options.mangle.properties) {
|
||||
|
||||
142
lib/output.js
142
lib/output.js
@@ -684,35 +684,41 @@ function OutputStream(options) {
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
var p = output.parent();
|
||||
// (-x) ** y
|
||||
if (p instanceof AST_Binary) return p.operator == "**" && p.left === this;
|
||||
// (x++).toString(3)
|
||||
// (typeof x).length
|
||||
return (p instanceof AST_Call || p instanceof AST_PropAccess) && p.expression === this;
|
||||
});
|
||||
|
||||
PARENS(AST_Sequence, function(output) {
|
||||
var p = output.parent();
|
||||
// [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
// [ 1, (2, 3), 4 ] ---> [ 1, 3, 4 ]
|
||||
return p instanceof AST_Array
|
||||
// () => (foo, bar)
|
||||
|| p instanceof AST_Arrow && p.value === this
|
||||
// () ---> (foo, bar)
|
||||
|| is_arrow(p) && p.value === this
|
||||
// await (foo, bar)
|
||||
|| p instanceof AST_Await
|
||||
// 1 + (2, 3) + 4 ==> 8
|
||||
// 1 + (2, 3) + 4 ---> 8
|
||||
|| p instanceof AST_Binary
|
||||
// new (foo, bar) or foo(1, (2, 3), 4)
|
||||
|| p instanceof AST_Call
|
||||
// (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_Conditional
|
||||
// { [(1, 2)]: 3 }[2] ==> 3
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
// [ a = (1, 2) ] = [] ---> a == 2
|
||||
|| p instanceof AST_DefaultValue
|
||||
// { [(1, 2)]: 3 }[2] ---> 3
|
||||
// { foo: (1, 2) }.foo ---> 2
|
||||
|| p instanceof AST_DestructuredKeyVal
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ---> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
// ...(foo, bar, baz)
|
||||
|| p instanceof AST_Spread
|
||||
// !(foo, bar, baz)
|
||||
|| p instanceof AST_Unary
|
||||
// var a = (1, 2), b = a + a; ==> b == 4
|
||||
// var a = (1, 2), b = a + a; ---> b == 4
|
||||
|| p instanceof AST_VarDef;
|
||||
});
|
||||
|
||||
@@ -720,11 +726,14 @@ function OutputStream(options) {
|
||||
var p = output.parent();
|
||||
// await (foo && bar)
|
||||
if (p instanceof AST_Await) return true;
|
||||
// this deals with precedence: 3 * (2 + 1)
|
||||
// this deals with precedence:
|
||||
// 3 * (2 + 1)
|
||||
// 3 - (2 - 1)
|
||||
// (1 ** 2) ** 3
|
||||
if (p instanceof AST_Binary) {
|
||||
var po = p.operator, pp = PRECEDENCE[po];
|
||||
var so = this.operator, sp = PRECEDENCE[so];
|
||||
return pp > sp || (pp == sp && this === p.right);
|
||||
return pp > sp || (pp == sp && this === p[po == "**" ? "left" : "right"]);
|
||||
}
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
@@ -771,18 +780,16 @@ function OutputStream(options) {
|
||||
// (new foo)(bar)
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
// (new Date).getTime(), (new Date)["getTime"]()
|
||||
return p instanceof AST_PropAccess;
|
||||
if (p instanceof AST_PropAccess) return true;
|
||||
// (new foo)`bar`
|
||||
if (p instanceof AST_Template) return p.tag === this;
|
||||
});
|
||||
|
||||
PARENS(AST_Number, function(output) {
|
||||
if (!output.option("galio")) return false;
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
var value = this.value;
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
return value < 0
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
|| output.option("galio") && /^0/.test(make_num(value));
|
||||
}
|
||||
return p instanceof AST_PropAccess && p.expression === this && /^0/.test(make_num(this.value));
|
||||
});
|
||||
|
||||
function needs_parens_assign_cond(self, output) {
|
||||
@@ -797,6 +804,8 @@ function OutputStream(options) {
|
||||
if (p instanceof AST_Conditional) return p.condition === self;
|
||||
// (a = foo)["prop"] —or— (a = foo).prop
|
||||
if (p instanceof AST_PropAccess) return p.expression === self;
|
||||
// (a = foo)`bar`
|
||||
if (p instanceof AST_Template) return p.tag === self;
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary) return true;
|
||||
}
|
||||
@@ -805,18 +814,23 @@ function OutputStream(options) {
|
||||
});
|
||||
PARENS(AST_Assign, function(output) {
|
||||
if (needs_parens_assign_cond(this, output)) return true;
|
||||
// v8 parser bug => workaround
|
||||
// f([1], [a] = []) => f([1], ([a] = []))
|
||||
// v8 parser bug ---> workaround
|
||||
// f([1], [a] = []) ---> f([1], ([a] = []))
|
||||
if (output.option("v8")) return this.left instanceof AST_Destructured;
|
||||
// ({ p: a } = o);
|
||||
if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output);
|
||||
});
|
||||
PARENS(AST_AsyncArrow, function(output) {
|
||||
return needs_parens_assign_cond(this, output);
|
||||
});
|
||||
PARENS(AST_Conditional, function(output) {
|
||||
return needs_parens_assign_cond(this, output);
|
||||
});
|
||||
|
||||
PARENS(AST_Await, function(output) {
|
||||
var p = output.parent();
|
||||
// (await x) ** y
|
||||
if (p instanceof AST_Binary) return p.operator == "**" && p.left === this;
|
||||
// new (await foo)
|
||||
// (await foo)(bar)
|
||||
if (p instanceof AST_Call) return p.expression === this;
|
||||
@@ -990,16 +1004,25 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
/* -----[ functions ]----- */
|
||||
DEFPRINT(AST_Arrow, function(output) {
|
||||
var self = this;
|
||||
if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg) {
|
||||
self.argnames[0].print(output);
|
||||
} else output.with_parens(function() {
|
||||
function print_funargs(self, output) {
|
||||
output.with_parens(function() {
|
||||
self.argnames.forEach(function(arg, i) {
|
||||
if (i) output.comma();
|
||||
arg.print(output);
|
||||
});
|
||||
if (self.rest) {
|
||||
if (self.argnames.length) output.comma();
|
||||
output.print("...");
|
||||
self.rest.print(output);
|
||||
}
|
||||
});
|
||||
}
|
||||
function print_arrow(self, output) {
|
||||
if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg && !self.rest) {
|
||||
self.argnames[0].print(output);
|
||||
} else {
|
||||
print_funargs(self, output);
|
||||
}
|
||||
output.space();
|
||||
output.print("=>");
|
||||
output.space();
|
||||
@@ -1008,18 +1031,21 @@ function OutputStream(options) {
|
||||
} else {
|
||||
print_braced(self, output, true);
|
||||
}
|
||||
}
|
||||
DEFPRINT(AST_Arrow, function(output) {
|
||||
print_arrow(this, output);
|
||||
});
|
||||
DEFPRINT(AST_AsyncArrow, function(output) {
|
||||
output.print("async");
|
||||
output.space();
|
||||
print_arrow(this, output);
|
||||
});
|
||||
function print_lambda(self, output) {
|
||||
if (self.name) {
|
||||
output.space();
|
||||
self.name.print(output);
|
||||
}
|
||||
output.with_parens(function() {
|
||||
self.argnames.forEach(function(arg, i) {
|
||||
if (i) output.comma();
|
||||
arg.print(output);
|
||||
});
|
||||
});
|
||||
print_funargs(self, output);
|
||||
output.space();
|
||||
print_braced(self, output, true);
|
||||
}
|
||||
@@ -1200,7 +1226,7 @@ function OutputStream(options) {
|
||||
if (noin) node.walk(new TreeWalker(function(node) {
|
||||
if (parens) return true;
|
||||
if (node instanceof AST_Binary && node.operator == "in") return parens = true;
|
||||
if (node instanceof AST_Scope && !(node instanceof AST_Arrow && node.value)) return true;
|
||||
if (node instanceof AST_Scope && !(is_arrow(node) && node.value)) return true;
|
||||
}));
|
||||
node.print(output, parens);
|
||||
}
|
||||
@@ -1218,6 +1244,15 @@ function OutputStream(options) {
|
||||
}
|
||||
});
|
||||
|
||||
DEFPRINT(AST_DefaultValue, function(output) {
|
||||
var self = this;
|
||||
self.name.print(output);
|
||||
output.space();
|
||||
output.print("=");
|
||||
output.space();
|
||||
self.value.print(output);
|
||||
});
|
||||
|
||||
/* -----[ other expressions ]----- */
|
||||
function print_call_args(self, output) {
|
||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||
@@ -1344,25 +1379,30 @@ function OutputStream(options) {
|
||||
} : noop);
|
||||
});
|
||||
DEFPRINT(AST_DestructuredArray, function(output) {
|
||||
var a = this.elements, len = a.length;
|
||||
output.with_square(len > 0 ? function() {
|
||||
var a = this.elements, len = a.length, rest = this.rest;
|
||||
output.with_square(len || rest ? function() {
|
||||
output.space();
|
||||
a.forEach(function(exp, i) {
|
||||
if (i) output.comma();
|
||||
exp.print(output);
|
||||
});
|
||||
if (rest) {
|
||||
if (len) output.comma();
|
||||
output.print("...");
|
||||
rest.print(output);
|
||||
} else if (a[len - 1] instanceof AST_Hole) {
|
||||
// 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 && exp instanceof AST_Hole)
|
||||
output.comma();
|
||||
});
|
||||
output.comma();
|
||||
}
|
||||
output.space();
|
||||
} : noop);
|
||||
});
|
||||
DEFPRINT(AST_DestructuredKeyVal, print_key_value);
|
||||
DEFPRINT(AST_DestructuredObject, function(output) {
|
||||
var props = this.properties;
|
||||
if (props.length > 0) output.with_block(function() {
|
||||
var props = this.properties, len = props.length, rest = this.rest;
|
||||
if (len || rest) output.with_block(function() {
|
||||
props.forEach(function(prop, i) {
|
||||
if (i) {
|
||||
output.print(",");
|
||||
@@ -1371,6 +1411,15 @@ function OutputStream(options) {
|
||||
output.indent();
|
||||
prop.print(output);
|
||||
});
|
||||
if (rest) {
|
||||
if (len) {
|
||||
output.print(",");
|
||||
output.newline();
|
||||
}
|
||||
output.indent();
|
||||
output.print("...");
|
||||
rest.print(output);
|
||||
}
|
||||
output.newline();
|
||||
});
|
||||
else print_braced_empty(this, output);
|
||||
@@ -1441,6 +1490,19 @@ function OutputStream(options) {
|
||||
DEFPRINT(AST_This, function(output) {
|
||||
output.print("this");
|
||||
});
|
||||
DEFPRINT(AST_Template, function(output) {
|
||||
var self = this;
|
||||
if (self.tag) self.tag.print(output);
|
||||
output.print("`");
|
||||
for (var i = 0; i < self.expressions.length; i++) {
|
||||
output.print(self.strings[i]);
|
||||
output.print("${");
|
||||
self.expressions[i].print(output);
|
||||
output.print("}");
|
||||
}
|
||||
output.print(self.strings[i]);
|
||||
output.print("`");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(output) {
|
||||
output.print(this.value);
|
||||
});
|
||||
|
||||
449
lib/parse.js
449
lib/parse.js
@@ -81,6 +81,7 @@ var OPERATORS = makePredicate([
|
||||
"*",
|
||||
"/",
|
||||
"%",
|
||||
"**",
|
||||
">>",
|
||||
"<<",
|
||||
">>>",
|
||||
@@ -112,7 +113,7 @@ var OPERATORS = makePredicate([
|
||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
||||
var PUNC_BEFORE_EXPRESSION = "[{(,;:";
|
||||
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + ")}]";
|
||||
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`)}]";
|
||||
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
||||
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
||||
|
||||
@@ -144,6 +145,43 @@ function is_identifier_string(str) {
|
||||
return /^[a-z_$][a-z0-9_$]*$/i.test(str);
|
||||
}
|
||||
|
||||
function decode_escape_sequence(seq) {
|
||||
switch (seq[0]) {
|
||||
case "b": return "\b";
|
||||
case "f": return "\f";
|
||||
case "n": return "\n";
|
||||
case "r": return "\r";
|
||||
case "t": return "\t";
|
||||
case "u":
|
||||
var code;
|
||||
if (seq.length == 5) {
|
||||
code = seq.slice(1);
|
||||
} else if (seq[1] == "{" && seq.slice(-1) == "}") {
|
||||
code = seq.slice(2, -1);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
var num = parseInt(code, 16);
|
||||
if (num < 0 || isNaN(num)) return;
|
||||
if (num < 0x10000) return String.fromCharCode(num);
|
||||
if (num > 0x10ffff) return;
|
||||
return String.fromCharCode((num >> 10) + 0xd7c0) + String.fromCharCode((num & 0x03ff) + 0xdc00);
|
||||
case "v": return "\u000b";
|
||||
case "x":
|
||||
if (seq.length != 3) return;
|
||||
var num = parseInt(seq.slice(1), 16);
|
||||
if (num < 0 || isNaN(num)) return;
|
||||
return String.fromCharCode(num);
|
||||
case "\r":
|
||||
case "\n":
|
||||
return "";
|
||||
default:
|
||||
if (seq == "0") return "\0";
|
||||
if (seq[0] >= "0" && seq[0] <= "9") return;
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
||||
function parse_js_number(num) {
|
||||
var match;
|
||||
if (match = RE_BIN_NUMBER.exec(num)) return parseInt(match[1], 2);
|
||||
@@ -190,7 +228,28 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
regex_allowed : false,
|
||||
comments_before : [],
|
||||
directives : {},
|
||||
directive_stack : []
|
||||
directive_stack : [],
|
||||
read_template : with_eof_error("Unterminated template literal", function(strings) {
|
||||
var s = "";
|
||||
for (;;) {
|
||||
var ch = next(true, true);
|
||||
switch (ch) {
|
||||
case "\\":
|
||||
ch += next(true, true);
|
||||
break;
|
||||
case "`":
|
||||
strings.push(s);
|
||||
return;
|
||||
case "$":
|
||||
if (peek() == "{") {
|
||||
next();
|
||||
strings.push(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
s += ch;
|
||||
}
|
||||
}),
|
||||
};
|
||||
var prev_was_dot = false;
|
||||
|
||||
@@ -280,9 +339,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
}
|
||||
|
||||
function read_while(pred) {
|
||||
var ret = "", ch, i = 0;
|
||||
while ((ch = peek()) && pred(ch, i++))
|
||||
ret += next();
|
||||
var ret = "", ch;
|
||||
while ((ch = peek()) && pred(ch)) ret += next();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -292,16 +350,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function read_num(prefix) {
|
||||
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
|
||||
var num = read_while(function(ch, i) {
|
||||
var num = read_while(function(ch) {
|
||||
var code = ch.charCodeAt(0);
|
||||
switch (code) {
|
||||
case 120: case 88: // xX
|
||||
return has_x ? false : (has_x = true);
|
||||
case 101: case 69: // eE
|
||||
return has_x ? true : has_e ? false : (has_e = after_e = true);
|
||||
case 45: // -
|
||||
return after_e || (i == 0 && !prefix);
|
||||
case 43: // +
|
||||
case 43: case 45: // +-
|
||||
return after_e;
|
||||
case (after_e = false, 46): // .
|
||||
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
||||
@@ -315,41 +371,29 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
num = num.replace(has_x ? /([1-9a-f]|.0)_(?=[0-9a-f])/gi : /([1-9]|.0)_(?=[0-9])/gi, "$1");
|
||||
}
|
||||
var valid = parse_js_number(num);
|
||||
if (!isNaN(valid)) return token("num", valid);
|
||||
parse_error("Invalid syntax: " + num);
|
||||
if (isNaN(valid)) parse_error("Invalid syntax: " + num);
|
||||
if (has_dot || has_e || peek() != "n") return token("num", valid);
|
||||
return token("bigint", num.toLowerCase() + next());
|
||||
}
|
||||
|
||||
function read_escaped_char(in_string) {
|
||||
var ch = next(true, in_string);
|
||||
switch (ch.charCodeAt(0)) {
|
||||
case 110: return "\n";
|
||||
case 114: return "\r";
|
||||
case 116: return "\t";
|
||||
case 98: return "\b";
|
||||
case 118: return "\u000b"; // \v
|
||||
case 102: return "\f";
|
||||
case 120: return String.fromCharCode(hex_bytes(2)); // \x
|
||||
case 117: // \u
|
||||
if (peek() != "{") return String.fromCharCode(hex_bytes(4));
|
||||
next();
|
||||
var num = 0;
|
||||
do {
|
||||
var digit = parseInt(next(true), 16);
|
||||
if (isNaN(digit)) parse_error("Invalid hex-character pattern in string");
|
||||
num = num * 16 + digit;
|
||||
} while (peek() != "}");
|
||||
next();
|
||||
if (num < 0x10000) return String.fromCharCode(num);
|
||||
if (num > 0x10ffff) parse_error("Invalid character code: " + num);
|
||||
return String.fromCharCode((num >> 10) + 0xd7c0) + String.fromCharCode((num & 0x03ff) + 0xdc00);
|
||||
case 13: // \r
|
||||
// DOS newline
|
||||
if (peek() == "\n") next(true, in_string);
|
||||
case 10: return ""; // \n
|
||||
var seq = next(true, in_string);
|
||||
if (seq >= "0" && seq <= "7") return read_octal_escape_sequence(seq);
|
||||
if (seq == "u") {
|
||||
var ch = next(true, in_string);
|
||||
seq += ch;
|
||||
if (ch != "{") {
|
||||
seq += next(true, in_string) + next(true, in_string) + next(true, in_string);
|
||||
} else do {
|
||||
ch = next(true, in_string);
|
||||
seq += ch;
|
||||
} while (ch != "}");
|
||||
} else if (seq == "x") {
|
||||
seq += next(true, in_string) + next(true, in_string);
|
||||
}
|
||||
if (ch >= "0" && ch <= "7")
|
||||
return read_octal_escape_sequence(ch);
|
||||
return ch;
|
||||
var str = decode_escape_sequence(seq);
|
||||
if (typeof str != "string") parse_error("Invalid escape sequence: \\" + seq);
|
||||
return str;
|
||||
}
|
||||
|
||||
function read_octal_escape_sequence(ch) {
|
||||
@@ -368,17 +412,6 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
return String.fromCharCode(parseInt(ch, 8));
|
||||
}
|
||||
|
||||
function hex_bytes(n) {
|
||||
var num = 0;
|
||||
for (; n > 0; --n) {
|
||||
var digit = parseInt(next(true), 16);
|
||||
if (isNaN(digit))
|
||||
parse_error("Invalid hex-character pattern in string");
|
||||
num = (num << 4) | digit;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
var read_string = with_eof_error("Unterminated string constant", function(quote_char) {
|
||||
var quote = next(), ret = "";
|
||||
for (;;) {
|
||||
@@ -632,10 +665,11 @@ var PRECEDENCE = function(a, ret) {
|
||||
["<", ">", "<=", ">=", "in", "instanceof"],
|
||||
[">>", "<<", ">>>"],
|
||||
["+", "-"],
|
||||
["*", "/", "%"]
|
||||
["*", "/", "%"],
|
||||
["**"],
|
||||
], {});
|
||||
|
||||
var ATOMIC_START_TOKEN = makePredicate("atom num regexp string");
|
||||
var ATOMIC_START_TOKEN = makePredicate("atom bigint num regexp string");
|
||||
|
||||
/* -----[ Parser ]----- */
|
||||
|
||||
@@ -737,7 +771,7 @@ function parse($TEXT, options) {
|
||||
|
||||
function semicolon(optional) {
|
||||
if (is("punc", ";")) next();
|
||||
else if (!optional && !can_insert_semicolon()) expect_token("punc", ";");
|
||||
else if (!optional && !can_insert_semicolon()) expect(";");
|
||||
}
|
||||
|
||||
function parenthesised() {
|
||||
@@ -783,6 +817,7 @@ function parse($TEXT, options) {
|
||||
semicolon();
|
||||
return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
|
||||
case "num":
|
||||
case "bigint":
|
||||
case "regexp":
|
||||
case "operator":
|
||||
case "atom":
|
||||
@@ -796,13 +831,14 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return function_(AST_AsyncDefun);
|
||||
}
|
||||
break;
|
||||
case "await":
|
||||
if (S.in_async) return simple_statement();
|
||||
default:
|
||||
return is_token(peek(), "punc", ":")
|
||||
? labeled_statement()
|
||||
: simple_statement();
|
||||
break;
|
||||
}
|
||||
return is_token(peek(), "punc", ":")
|
||||
? labeled_statement()
|
||||
: simple_statement();
|
||||
|
||||
case "punc":
|
||||
switch (S.token.value) {
|
||||
@@ -814,6 +850,7 @@ function parse($TEXT, options) {
|
||||
});
|
||||
case "[":
|
||||
case "(":
|
||||
case "`":
|
||||
return simple_statement();
|
||||
case ";":
|
||||
S.in_directives = false;
|
||||
@@ -1039,36 +1076,74 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
function to_funarg(node) {
|
||||
if (node instanceof AST_Array) return new AST_DestructuredArray({
|
||||
if (node instanceof AST_Array) {
|
||||
var rest = null;
|
||||
if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
|
||||
rest = to_funarg(node.elements.pop().expression);
|
||||
}
|
||||
return new AST_DestructuredArray({
|
||||
start: node.start,
|
||||
elements: node.elements.map(to_funarg),
|
||||
rest: rest,
|
||||
end: node.end,
|
||||
});
|
||||
}
|
||||
if (node instanceof AST_Assign) return new AST_DefaultValue({
|
||||
start: node.start,
|
||||
elements: node.elements.map(function(node) {
|
||||
return node instanceof AST_Hole ? node : to_funarg(node);
|
||||
}),
|
||||
end: node.end,
|
||||
});
|
||||
if (node instanceof AST_Object) return new AST_DestructuredObject({
|
||||
start: node.start,
|
||||
properties: node.properties.map(function(prop) {
|
||||
if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
|
||||
return new AST_DestructuredKeyVal({
|
||||
start: prop.start,
|
||||
key: prop.key,
|
||||
value: to_funarg(prop.value),
|
||||
end: prop.end,
|
||||
});
|
||||
}),
|
||||
name: to_funarg(node.left),
|
||||
value: node.right,
|
||||
end: node.end,
|
||||
});
|
||||
if (node instanceof AST_DefaultValue) {
|
||||
node.name = to_funarg(node.name);
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_DestructuredArray) {
|
||||
node.elements = node.elements.map(to_funarg);
|
||||
if (node.rest) node.rest = to_funarg(node.rest);
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_DestructuredObject) {
|
||||
node.properties.forEach(function(prop) {
|
||||
prop.value = to_funarg(prop.value);
|
||||
});
|
||||
if (node.rest) node.rest = to_funarg(node.rest);
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_Hole) return node;
|
||||
if (node instanceof AST_Object) {
|
||||
var rest = null;
|
||||
if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
|
||||
rest = to_funarg(node.properties.pop().expression);
|
||||
}
|
||||
return new AST_DestructuredObject({
|
||||
start: node.start,
|
||||
properties: node.properties.map(function(prop) {
|
||||
if (!(prop instanceof AST_ObjectKeyVal)) token_error(prop.start, "Invalid destructuring assignment");
|
||||
return new AST_DestructuredKeyVal({
|
||||
start: prop.start,
|
||||
key: prop.key,
|
||||
value: to_funarg(prop.value),
|
||||
end: prop.end,
|
||||
});
|
||||
}),
|
||||
rest: rest,
|
||||
end: node.end,
|
||||
});
|
||||
}
|
||||
if (node instanceof AST_SymbolFunarg) return node;
|
||||
if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node);
|
||||
token_error(node.start, "Invalid arrow parameter");
|
||||
}
|
||||
|
||||
function arrow(exprs, start) {
|
||||
function arrow(exprs, start, async) {
|
||||
var was_async = S.in_async;
|
||||
S.in_async = false;
|
||||
S.in_async = async;
|
||||
var was_funarg = S.in_funarg;
|
||||
S.in_funarg = S.in_function;
|
||||
var argnames = exprs.map(to_funarg);
|
||||
var rest = exprs.rest || null;
|
||||
if (rest) rest = to_funarg(rest);
|
||||
S.in_funarg = was_funarg;
|
||||
expect("=>");
|
||||
var body, value;
|
||||
@@ -1094,9 +1169,10 @@ function parse($TEXT, options) {
|
||||
S.in_loop = loop;
|
||||
S.labels = labels;
|
||||
S.in_async = was_async;
|
||||
return new AST_Arrow({
|
||||
return new (async ? AST_AsyncArrow : AST_Arrow)({
|
||||
start: start,
|
||||
argnames: argnames,
|
||||
rest: rest,
|
||||
body: body,
|
||||
value: value,
|
||||
end: prev(),
|
||||
@@ -1122,7 +1198,7 @@ function parse($TEXT, options) {
|
||||
var was_funarg = S.in_funarg;
|
||||
S.in_funarg = S.in_function;
|
||||
var argnames = expr_list(")", !options.strict, false, function() {
|
||||
return maybe_destructured(AST_SymbolFunarg);
|
||||
return maybe_default(AST_SymbolFunarg);
|
||||
});
|
||||
S.in_funarg = was_funarg;
|
||||
var loop = S.in_loop;
|
||||
@@ -1136,6 +1212,7 @@ function parse($TEXT, options) {
|
||||
if (S.input.has_directive("use strict")) {
|
||||
if (name) strict_verify_symbol(name);
|
||||
argnames.forEach(strict_verify_symbol);
|
||||
if (argnames.rest) strict_verify_symbol(argnames.rest);
|
||||
}
|
||||
S.input.pop_directives_stack();
|
||||
--S.in_function;
|
||||
@@ -1145,6 +1222,7 @@ function parse($TEXT, options) {
|
||||
return new ctor({
|
||||
name: name,
|
||||
argnames: argnames,
|
||||
rest: argnames.rest || null,
|
||||
body: body
|
||||
});
|
||||
};
|
||||
@@ -1166,7 +1244,7 @@ function parse($TEXT, options) {
|
||||
expect("{");
|
||||
var a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
if (is("eof")) expect("}");
|
||||
a.push(statement());
|
||||
}
|
||||
next();
|
||||
@@ -1177,7 +1255,7 @@ function parse($TEXT, options) {
|
||||
expect("{");
|
||||
var a = [], branch, cur, default_branch, tmp;
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
if (is("eof")) expect("}");
|
||||
if (is("keyword", "case")) {
|
||||
if (branch) branch.end = prev();
|
||||
cur = [];
|
||||
@@ -1319,6 +1397,9 @@ function parse($TEXT, options) {
|
||||
case "num":
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
break;
|
||||
case "bigint":
|
||||
ret = new AST_BigInt({ start: tok, end: tok, value: tok.value });
|
||||
break;
|
||||
case "string":
|
||||
ret = new AST_String({
|
||||
start : tok,
|
||||
@@ -1355,6 +1436,11 @@ function parse($TEXT, options) {
|
||||
var start = S.token;
|
||||
if (is("punc")) {
|
||||
switch (start.value) {
|
||||
case "`":
|
||||
var tmpl = template(null);
|
||||
tmpl.start = start;
|
||||
tmpl.end = prev();
|
||||
return subscripts(tmpl, allow_calls);
|
||||
case "(":
|
||||
next();
|
||||
if (is("punc", ")")) {
|
||||
@@ -1393,16 +1479,9 @@ function parse($TEXT, options) {
|
||||
}
|
||||
unexpected();
|
||||
}
|
||||
var ctor;
|
||||
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
|
||||
if (is("keyword", "function")) {
|
||||
next();
|
||||
ctor = AST_AsyncFunction;
|
||||
} else if (is("keyword", "function")) {
|
||||
ctor = AST_Function;
|
||||
}
|
||||
if (ctor) {
|
||||
next();
|
||||
var func = function_(ctor);
|
||||
var func = function_(AST_Function);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
@@ -1410,6 +1489,30 @@ function parse($TEXT, options) {
|
||||
if (is("name")) {
|
||||
var sym = _make_symbol(AST_SymbolRef, start);
|
||||
next();
|
||||
if (sym.name == "async") {
|
||||
if (is("keyword", "function")) {
|
||||
next();
|
||||
var func = function_(AST_AsyncFunction);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
}
|
||||
if (is("name")) {
|
||||
start = S.token;
|
||||
sym = _make_symbol(AST_SymbolRef, start);
|
||||
next();
|
||||
return arrow([ sym ], start, true);
|
||||
}
|
||||
if (is("punc", "(")) {
|
||||
var call = subscripts(sym, allow_calls);
|
||||
if (!is("punc", "=>")) return call;
|
||||
var args = call.args;
|
||||
if (args[args.length - 1] instanceof AST_Spread) {
|
||||
args.rest = args.pop().expression;
|
||||
}
|
||||
return arrow(args, start, true);
|
||||
}
|
||||
}
|
||||
return is("punc", "=>") ? arrow([ sym ], start) : subscripts(sym, allow_calls);
|
||||
}
|
||||
if (ATOMIC_START_TOKEN[S.token.type]) {
|
||||
@@ -1426,17 +1529,22 @@ function parse($TEXT, options) {
|
||||
if (allow_trailing_comma && is("punc", closing)) break;
|
||||
if (allow_empty && is("punc", ",")) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
} else if (parser === maybe_assign && is("operator", "...")) {
|
||||
} else if (!is("operator", "...")) {
|
||||
a.push(parser());
|
||||
} else if (parser === maybe_assign) {
|
||||
a.push(new AST_Spread({
|
||||
start: S.token,
|
||||
expression: (next(), parser()),
|
||||
end: prev(),
|
||||
}));
|
||||
} else {
|
||||
a.push(parser());
|
||||
next();
|
||||
a.rest = parser();
|
||||
if (a.rest instanceof AST_DefaultValue) token_error(a.rest.start, "Invalid rest parameter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
next();
|
||||
expect(closing);
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1468,6 +1576,32 @@ function parse($TEXT, options) {
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (is_token(peek(), "operator", "=")) {
|
||||
var name = as_symbol(AST_SymbolRef);
|
||||
next();
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: start.value,
|
||||
value: new AST_Assign({
|
||||
start: start,
|
||||
left: name,
|
||||
operator: "=",
|
||||
right: maybe_assign(),
|
||||
end: prev(),
|
||||
}),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (is_token(peek(), "punc", ",") || is_token(peek(), "punc", "}")) {
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: start.value,
|
||||
value: as_symbol(AST_SymbolRef),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
var key = as_property_key();
|
||||
if (is("punc", "(")) {
|
||||
var func_start = S.token;
|
||||
@@ -1492,15 +1626,6 @@ function parse($TEXT, options) {
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (is("punc", ",") || is("punc", "}")) {
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: _make_symbol(AST_SymbolRef, start),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (start.type == "name") switch (key) {
|
||||
case "async":
|
||||
key = as_property_key();
|
||||
@@ -1561,9 +1686,8 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
function as_name() {
|
||||
if (!is("name")) expect_token("name");
|
||||
var name = S.token.value;
|
||||
next();
|
||||
expect_token("name");
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -1599,17 +1723,19 @@ function parse($TEXT, options) {
|
||||
var start = S.token;
|
||||
if (is("punc", "[")) {
|
||||
next();
|
||||
var elements = expr_list("]", !options.strict, true, function() {
|
||||
return maybe_default(type);
|
||||
});
|
||||
return new AST_DestructuredArray({
|
||||
start: start,
|
||||
elements: expr_list("]", !options.strict, true, function() {
|
||||
return maybe_destructured(type);
|
||||
}),
|
||||
elements: elements,
|
||||
rest: elements.rest || null,
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
if (is("punc", "{")) {
|
||||
next();
|
||||
var first = true, a = [];
|
||||
var first = true, a = [], rest = null;
|
||||
while (!is("punc", "}")) {
|
||||
if (first) first = false; else expect(",");
|
||||
// allow trailing comma
|
||||
@@ -1621,28 +1747,57 @@ function parse($TEXT, options) {
|
||||
a.push(new AST_DestructuredKeyVal({
|
||||
start: key_start,
|
||||
key: key,
|
||||
value: maybe_destructured(type),
|
||||
value: maybe_default(type),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (is("operator", "...")) {
|
||||
next();
|
||||
rest = maybe_destructured(type);
|
||||
break;
|
||||
}
|
||||
var name = as_symbol(type);
|
||||
if (is("operator", "=")) {
|
||||
next();
|
||||
name = new AST_DefaultValue({
|
||||
start: name.start,
|
||||
name: name,
|
||||
value: maybe_assign(),
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
a.push(new AST_DestructuredKeyVal({
|
||||
start: key_start,
|
||||
key: key_start.value,
|
||||
value: as_symbol(type),
|
||||
value: name,
|
||||
end: prev(),
|
||||
}));
|
||||
}
|
||||
next();
|
||||
expect("}");
|
||||
return new AST_DestructuredObject({
|
||||
start: start,
|
||||
properties: a,
|
||||
rest: rest,
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
return as_symbol(type);
|
||||
}
|
||||
|
||||
function maybe_default(type) {
|
||||
var start = S.token;
|
||||
var name = maybe_destructured(type);
|
||||
if (!is("operator", "=")) return name;
|
||||
next();
|
||||
return new AST_DefaultValue({
|
||||
start: start,
|
||||
name: name,
|
||||
value: maybe_assign(),
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
|
||||
function mark_pure(call) {
|
||||
var start = call.start;
|
||||
var comments = start.comments_before;
|
||||
@@ -1656,6 +1811,23 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function template(tag) {
|
||||
var read = S.input.context().read_template;
|
||||
var strings = [];
|
||||
var expressions = [];
|
||||
while (read(strings)) {
|
||||
next();
|
||||
expressions.push(expression());
|
||||
if (!is("punc", "}")) unexpected();
|
||||
}
|
||||
next();
|
||||
return new AST_Template({
|
||||
expressions: expressions,
|
||||
strings: strings,
|
||||
tag: tag,
|
||||
});
|
||||
}
|
||||
|
||||
var subscripts = function(expr, allow_calls) {
|
||||
var start = expr.start;
|
||||
if (is("punc", ".")) {
|
||||
@@ -1689,6 +1861,12 @@ function parse($TEXT, options) {
|
||||
mark_pure(call);
|
||||
return subscripts(call, true);
|
||||
}
|
||||
if (is("punc", "`")) {
|
||||
var tmpl = template(expr);
|
||||
tmpl.start = expr.start;
|
||||
tmpl.end = prev();
|
||||
return subscripts(tmpl, allow_calls);
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
@@ -1747,7 +1925,7 @@ function parse($TEXT, options) {
|
||||
var prec = op != null ? PRECEDENCE[op] : null;
|
||||
if (prec != null && prec > min_prec) {
|
||||
next();
|
||||
var right = expr_op(maybe_await(), prec, no_in);
|
||||
var right = expr_op(maybe_await(), op == "**" ? prec - 1 : prec, no_in);
|
||||
return expr_op(new AST_Binary({
|
||||
start : left.start,
|
||||
left : left,
|
||||
@@ -1787,22 +1965,47 @@ function parse($TEXT, options) {
|
||||
|
||||
function to_destructured(node) {
|
||||
if (node instanceof AST_Array) {
|
||||
var rest = null;
|
||||
if (node.elements[node.elements.length - 1] instanceof AST_Spread) {
|
||||
rest = to_destructured(node.elements.pop().expression);
|
||||
if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
|
||||
}
|
||||
var elements = node.elements.map(to_destructured);
|
||||
return all(elements, function(node) {
|
||||
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
|
||||
return node instanceof AST_DefaultValue
|
||||
|| node instanceof AST_Destructured
|
||||
|| node instanceof AST_Hole
|
||||
|| is_assignable(node);
|
||||
}) ? new AST_DestructuredArray({
|
||||
start: node.start,
|
||||
elements: elements,
|
||||
rest: rest,
|
||||
end: node.end,
|
||||
}) : node;
|
||||
}
|
||||
if (node instanceof AST_Assign) {
|
||||
var name = to_destructured(node.left);
|
||||
return name instanceof AST_Destructured || is_assignable(name) ? new AST_DefaultValue({
|
||||
start: node.start,
|
||||
name: name,
|
||||
value: node.right,
|
||||
end: node.end,
|
||||
}) : node;
|
||||
}
|
||||
if (!(node instanceof AST_Object)) return node;
|
||||
var rest = null;
|
||||
if (node.properties[node.properties.length - 1] instanceof AST_Spread) {
|
||||
rest = to_destructured(node.properties.pop().expression);
|
||||
if (!(rest instanceof AST_Destructured || is_assignable(rest))) return node;
|
||||
}
|
||||
var props = [];
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
if (!(prop instanceof AST_ObjectKeyVal)) return node;
|
||||
var value = to_destructured(prop.value);
|
||||
if (!(value instanceof AST_Destructured || is_assignable(value))) return node;
|
||||
if (!(value instanceof AST_DefaultValue || value instanceof AST_Destructured || is_assignable(value))) {
|
||||
return node;
|
||||
}
|
||||
props.push(new AST_DestructuredKeyVal({
|
||||
start: prop.start,
|
||||
key: prop.key,
|
||||
@@ -1813,6 +2016,7 @@ function parse($TEXT, options) {
|
||||
return new AST_DestructuredObject({
|
||||
start: node.start,
|
||||
properties: props,
|
||||
rest: rest,
|
||||
end: node.end,
|
||||
});
|
||||
}
|
||||
@@ -1840,15 +2044,20 @@ function parse($TEXT, options) {
|
||||
var start = S.token;
|
||||
var exprs = [];
|
||||
while (true) {
|
||||
if (maybe_arrow && is("operator", "...")) {
|
||||
next();
|
||||
exprs.rest = maybe_destructured(AST_SymbolFunarg);
|
||||
break;
|
||||
}
|
||||
exprs.push(maybe_assign(no_in));
|
||||
if (!is("punc", ",")) break;
|
||||
next();
|
||||
if (maybe_arrow && is("punc", ")") && is_token(peek(), "punc", "=>")) break;
|
||||
}
|
||||
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||
start : start,
|
||||
expressions : exprs,
|
||||
end : prev()
|
||||
return exprs.length == 1 && !exprs.rest ? exprs[0] : new AST_Sequence({
|
||||
start: start,
|
||||
expressions: exprs,
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1861,7 +2070,9 @@ function parse($TEXT, options) {
|
||||
|
||||
if (options.expression) {
|
||||
handle_regexp();
|
||||
return expression();
|
||||
var exp = expression();
|
||||
expect_token("eof");
|
||||
return exp;
|
||||
}
|
||||
|
||||
return function() {
|
||||
|
||||
@@ -228,7 +228,7 @@ function mangle_properties(ast, options) {
|
||||
var mangled = cache.get(name);
|
||||
if (!mangled) {
|
||||
if (debug) {
|
||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo ---> o._$foo$NNN_.
|
||||
var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
|
||||
if (can_mangle(debug_mangled)) mangled = debug_mangled;
|
||||
}
|
||||
|
||||
86
lib/scope.js
86
lib/scope.js
@@ -48,7 +48,6 @@ function SymbolDef(id, scope, orig, init) {
|
||||
this.global = false;
|
||||
this.id = id;
|
||||
this.init = init;
|
||||
this.lambda = orig instanceof AST_SymbolLambda;
|
||||
this.mangled_name = null;
|
||||
this.name = orig.name;
|
||||
this.orig = [ orig ];
|
||||
@@ -102,6 +101,14 @@ SymbolDef.prototype = {
|
||||
|
||||
var unary_side_effects = makePredicate("delete ++ --");
|
||||
|
||||
function is_lhs(node, parent) {
|
||||
if (parent instanceof AST_Assign) return parent.left === node && node;
|
||||
if (parent instanceof AST_DefaultValue) return parent.name === node && node;
|
||||
if (parent instanceof AST_Destructured) return node;
|
||||
if (parent instanceof AST_DestructuredKeyVal) return node;
|
||||
if (parent instanceof AST_Unary) return unary_side_effects[parent.operator] && parent.expression;
|
||||
}
|
||||
|
||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
options = defaults(options, {
|
||||
cache: null,
|
||||
@@ -120,6 +127,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
if (node.rest) node.rest.walk(tw);
|
||||
walk_body(node, tw);
|
||||
});
|
||||
return true;
|
||||
@@ -221,31 +229,33 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
if (node.rest) node.rest.walk(tw);
|
||||
in_arg.pop();
|
||||
if (node instanceof AST_Arrow && node.value) {
|
||||
node.value.walk(tw);
|
||||
} else {
|
||||
walk_body(node, tw);
|
||||
}
|
||||
walk_lambda(node, tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LoopControl) {
|
||||
if (node.label) node.label.thedef.references.push(node);
|
||||
return true;
|
||||
}
|
||||
// ensure mangling works if `catch` reuses a scope variable
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
var def = node.definition().redefined();
|
||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||
push_uniq(s.enclosed, def);
|
||||
if (s === def.scope) break;
|
||||
if (node instanceof AST_SymbolDeclaration) {
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
// ensure mangling works if `catch` reuses a scope variable
|
||||
var def = node.definition().redefined();
|
||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||
push_uniq(s.enclosed, def);
|
||||
if (s === def.scope) break;
|
||||
}
|
||||
} else if (node instanceof AST_SymbolConst) {
|
||||
// ensure compression works if `const` reuses a scope variable
|
||||
var redef = node.definition().redefined();
|
||||
if (redef) redef.const_redefs = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// ensure compression works if `const` reuses a scope variable
|
||||
if (node instanceof AST_SymbolConst) {
|
||||
var redef = node.definition().redefined();
|
||||
if (redef) redef.const_redefs = true;
|
||||
if (node.name != "arguments") return true;
|
||||
var parent = node instanceof AST_SymbolVar && tw.parent();
|
||||
if (parent instanceof AST_VarDef && !parent.value) return true;
|
||||
var sym = node.scope.resolve().find_variable("arguments");
|
||||
if (sym && is_arguments(sym)) sym.scope.uses_arguments = 3;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
@@ -265,13 +275,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
if (!sym) {
|
||||
sym = self.def_global(node);
|
||||
} else if (name == "arguments"
|
||||
&& sym.orig[0] instanceof AST_SymbolFunarg
|
||||
&& !(sym.orig[1] instanceof AST_SymbolFunarg)
|
||||
&& !(sym.scope instanceof AST_Arrow)) {
|
||||
} else if (name == "arguments" && is_arguments(sym)) {
|
||||
var parent = tw.parent();
|
||||
if (parent instanceof AST_Assign && parent.left === node
|
||||
|| parent instanceof AST_Unary && unary_side_effects[parent.operator]) {
|
||||
if (is_lhs(node, parent)) {
|
||||
sym.scope.uses_arguments = 3;
|
||||
} else if (sym.scope.uses_arguments < 2
|
||||
&& !(parent instanceof AST_PropAccess && parent.expression === node)) {
|
||||
@@ -312,8 +318,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
if (node instanceof AST_SymbolLambda) {
|
||||
var def = node.thedef;
|
||||
redefine(node, node.scope.parent_scope.resolve());
|
||||
if (typeof node.thedef.init !== "undefined") {
|
||||
if (!redefine(node, node.scope.parent_scope.resolve())) {
|
||||
delete def.defun;
|
||||
} else if (typeof node.thedef.init !== "undefined") {
|
||||
node.thedef.init = false;
|
||||
} else if (def.init) {
|
||||
node.thedef.init = def.init;
|
||||
@@ -322,12 +329,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
}));
|
||||
|
||||
function is_arguments(sym) {
|
||||
return sym.orig[0] instanceof AST_SymbolFunarg
|
||||
&& !(sym.orig[1] instanceof AST_SymbolFunarg || sym.orig[2] instanceof AST_SymbolFunarg)
|
||||
&& !is_arrow(sym.scope);
|
||||
}
|
||||
|
||||
function redefine(node, scope) {
|
||||
var name = node.name;
|
||||
var old_def = node.thedef;
|
||||
if (!all(old_def.orig, function(sym) {
|
||||
return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet);
|
||||
})) return;
|
||||
})) return false;
|
||||
var new_def = scope.find_variable(name);
|
||||
if (new_def) {
|
||||
var redef = new_def.redefined();
|
||||
@@ -342,12 +355,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
old_def.defun = new_def.scope;
|
||||
old_def.forEach(function(node) {
|
||||
node.redef = true;
|
||||
node.redef = old_def;
|
||||
node.thedef = new_def;
|
||||
node.reference(options);
|
||||
});
|
||||
if (old_def.lambda) new_def.lambda = true;
|
||||
if (new_def.undeclared) self.variables.set(name, new_def);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -387,6 +400,9 @@ AST_Scope.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
AST_Arrow.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
});
|
||||
AST_AsyncArrow.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
});
|
||||
AST_Lambda.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_scope_vars(this, parent_scope);
|
||||
this.uses_arguments = false;
|
||||
@@ -512,6 +528,7 @@ function _default_mangler_options(options) {
|
||||
keep_fnames : false,
|
||||
reserved : [],
|
||||
toplevel : false,
|
||||
v8 : false,
|
||||
webkit : false,
|
||||
});
|
||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||
@@ -543,7 +560,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
// lname is incremented when we get to the AST_Label
|
||||
var save_nesting = lname;
|
||||
descend();
|
||||
lname = save_nesting;
|
||||
if (!options.v8 || !in_label(tw)) lname = save_nesting;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_BlockScope) {
|
||||
@@ -602,6 +619,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
if (!(sym instanceof AST_SymbolConst)) return false;
|
||||
var scope = def.scope.resolve();
|
||||
if (def.scope === scope) return false;
|
||||
if (def.scope.parent_scope.find_variable(sym.name)) return false;
|
||||
redef = scope.def_variable(sym);
|
||||
scope.to_mangle.push(redef);
|
||||
}
|
||||
@@ -616,6 +634,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
sym.thedef = def;
|
||||
}
|
||||
}
|
||||
|
||||
function in_label(tw) {
|
||||
var level = 0, parent;
|
||||
while (parent = tw.parent(level++)) {
|
||||
if (parent instanceof AST_Block) return parent instanceof AST_Toplevel && !options.toplevel;
|
||||
if (parent instanceof AST_LabeledStatement) return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||
|
||||
@@ -144,7 +144,9 @@ function SourceMap(options) {
|
||||
add(source, gen_line, gen_col, orig_line, orig_col, name);
|
||||
} : add,
|
||||
setSourceContent: sources_content ? function(source, content) {
|
||||
sources_content[source] = content;
|
||||
if (!(source in sources_content)) {
|
||||
sources_content[source] = content;
|
||||
}
|
||||
} : noop,
|
||||
toString: function() {
|
||||
return JSON.stringify({
|
||||
|
||||
@@ -126,19 +126,27 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
self.name = self.name.transform(tw);
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_DefaultValue, function(self, tw) {
|
||||
self.name = self.name.transform(tw);
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_Lambda, function(self, tw) {
|
||||
if (self.name) self.name = self.name.transform(tw);
|
||||
self.argnames = do_list(self.argnames, tw);
|
||||
if (self.rest) self.rest = self.rest.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Arrow, function(self, tw) {
|
||||
function transform_arrow(self, tw) {
|
||||
self.argnames = do_list(self.argnames, tw);
|
||||
if (self.rest) self.rest = self.rest.transform(tw);
|
||||
if (self.value) {
|
||||
self.value = self.value.transform(tw);
|
||||
} else {
|
||||
self.body = do_list(self.body, tw);
|
||||
}
|
||||
});
|
||||
}
|
||||
DEF(AST_Arrow, transform_arrow);
|
||||
DEF(AST_AsyncArrow, transform_arrow);
|
||||
DEF(AST_Call, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.args = do_list(self.args, tw);
|
||||
@@ -176,6 +184,7 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
});
|
||||
DEF(AST_DestructuredArray, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
if (self.rest) self.rest = self.rest.transform(tw);
|
||||
});
|
||||
DEF(AST_DestructuredKeyVal, function(self, tw) {
|
||||
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||
@@ -183,6 +192,7 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
});
|
||||
DEF(AST_DestructuredObject, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
if (self.rest) self.rest = self.rest.transform(tw);
|
||||
});
|
||||
DEF(AST_Object, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
@@ -191,6 +201,10 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_Template, function(self, tw) {
|
||||
if (self.tag) self.tag = self.tag.transform(tw);
|
||||
self.expressions = do_list(self.expressions, tw);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
node.DEFMETHOD("transform", function(tw, in_list) {
|
||||
var x, y;
|
||||
|
||||
@@ -241,7 +241,7 @@ function HOP(obj, prop) {
|
||||
function first_in_statement(stack, arrow) {
|
||||
var node = stack.parent(-1);
|
||||
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
||||
if (p instanceof AST_Arrow) {
|
||||
if (is_arrow(p)) {
|
||||
return arrow && p.value === node;
|
||||
} else if (p instanceof AST_Binary) {
|
||||
if (p.left === node) continue;
|
||||
@@ -255,6 +255,8 @@ function first_in_statement(stack, arrow) {
|
||||
if (p.expressions[0] === node) continue;
|
||||
} else if (p instanceof AST_Statement) {
|
||||
return p.body === node;
|
||||
} else if (p instanceof AST_Template) {
|
||||
if (p.tag === node) continue;
|
||||
} else if (p instanceof AST_UnaryPostfix) {
|
||||
if (p.expression === node) continue;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.12.3",
|
||||
"version": "3.12.7",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
require("../tools/exit");
|
||||
require("../tools/tty");
|
||||
|
||||
var assert = require("assert");
|
||||
var child_process = require("child_process");
|
||||
@@ -209,7 +209,7 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
|
||||
} else {
|
||||
var toplevel = sandbox.has_toplevel(options);
|
||||
var expected = stdout[toplevel ? 1 : 0];
|
||||
var actual = run_code(result.code, toplevel);
|
||||
var actual = sandbox.run_code(result.code, toplevel);
|
||||
if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
|
||||
actual = expected;
|
||||
}
|
||||
@@ -244,11 +244,6 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function run_code(code, toplevel) {
|
||||
var result = sandbox.run_code(code, toplevel);
|
||||
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
||||
}
|
||||
|
||||
function test_case(test) {
|
||||
log(" Running test [{name}]", { name: test.name });
|
||||
U.AST_Node.enable_validation();
|
||||
@@ -380,7 +375,7 @@ function test_case(test) {
|
||||
}
|
||||
}
|
||||
if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||
var stdout = [ run_code(input_code), run_code(input_code, true) ];
|
||||
var stdout = [ sandbox.run_code(input_code), sandbox.run_code(input_code, true) ];
|
||||
var toplevel = sandbox.has_toplevel({
|
||||
compress: test.options,
|
||||
mangle: test.mangle
|
||||
@@ -409,7 +404,7 @@ function test_case(test) {
|
||||
});
|
||||
return false;
|
||||
}
|
||||
actual = run_code(output_code, toplevel);
|
||||
actual = sandbox.run_code(output_code, toplevel);
|
||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||
log([
|
||||
"!!! failed",
|
||||
|
||||
@@ -78,7 +78,7 @@ replace_index_strict: {
|
||||
]
|
||||
}
|
||||
|
||||
replace_index_keep_fargs: {
|
||||
replace_index_drop_fargs_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
evaluate: true,
|
||||
@@ -101,6 +101,13 @@ replace_index_keep_fargs: {
|
||||
var arguments;
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
(function() {
|
||||
var arguments = {
|
||||
1: "foo",
|
||||
foo: "bar",
|
||||
};
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
}
|
||||
expect: {
|
||||
var arguments = [];
|
||||
@@ -114,8 +121,15 @@ replace_index_keep_fargs: {
|
||||
(function(arguments) {
|
||||
console.log(arguments[1], arguments[1], arguments.foo);
|
||||
})("bar", 42);
|
||||
(function() {
|
||||
(function(argument_0, argument_1) {
|
||||
var arguments;
|
||||
console.log(argument_1, argument_1, arguments.foo);
|
||||
})("bar", 42);
|
||||
(function() {
|
||||
var arguments = {
|
||||
1: "foo",
|
||||
foo: "bar",
|
||||
};
|
||||
console.log(arguments[1], arguments[1], arguments.foo);
|
||||
})("bar", 42);
|
||||
}
|
||||
@@ -125,10 +139,11 @@ replace_index_keep_fargs: {
|
||||
"42 42 undefined",
|
||||
"a a undefined",
|
||||
"42 42 undefined",
|
||||
"foo foo bar",
|
||||
]
|
||||
}
|
||||
|
||||
replace_index_keep_fargs_strict: {
|
||||
replace_index_drop_fargs_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
evaluate: true,
|
||||
@@ -412,7 +427,7 @@ issue_3273_global_strict_reduce_vars: {
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_keep_fargs_false: {
|
||||
issue_3273_drop_fargs_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: false,
|
||||
@@ -435,10 +450,10 @@ issue_3273_keep_fargs_false: {
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3273_keep_fargs_strict: {
|
||||
issue_3273_drop_fargs_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
@@ -633,7 +648,7 @@ issue_3282_2_passes: {
|
||||
issue_3420_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
@@ -655,7 +670,7 @@ issue_3420_1: {
|
||||
issue_3420_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
var foo = function() {
|
||||
@@ -675,7 +690,7 @@ issue_3420_2: {
|
||||
issue_3420_3: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
@@ -697,7 +712,7 @@ issue_3420_3: {
|
||||
issue_3420_4: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
!function() {
|
||||
@@ -722,7 +737,7 @@ issue_3420_4: {
|
||||
issue_3420_5: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
@@ -749,7 +764,7 @@ issue_3420_5: {
|
||||
issue_3420_6: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
@@ -767,7 +782,7 @@ issue_3420_6: {
|
||||
issue_3420_7: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
@@ -811,7 +826,7 @@ issue_4200: {
|
||||
issue_4291_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
@@ -831,7 +846,7 @@ issue_4291_1: {
|
||||
issue_4291_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
var a = function() {
|
||||
@@ -855,7 +870,7 @@ issue_4291_2: {
|
||||
issue_4397: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
|
||||
@@ -13,9 +13,10 @@ holes_and_undefined: {
|
||||
}
|
||||
}
|
||||
|
||||
constant_join: {
|
||||
constant_join_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
strings: true,
|
||||
unsafe: true,
|
||||
}
|
||||
@@ -57,7 +58,7 @@ constant_join: {
|
||||
var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join();
|
||||
var c6 = [ "1,2,,,foo,bar", baz() ].join();
|
||||
var d = "foo-3bar-baz";
|
||||
var e = [].join(foo + bar);
|
||||
var e = (foo, bar, "");
|
||||
var f = "";
|
||||
var g = "";
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ collapse_value: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -434,10 +434,50 @@ collapse_value: {
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
collapse_property_lambda: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: "strict",
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
f.g = () => 42;
|
||||
return f.g();
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
return (f.g = () => 42)();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
drop_return: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(a => {
|
||||
while (!console);
|
||||
return console.log(a);
|
||||
})(42);
|
||||
}
|
||||
expect: {
|
||||
(a => {
|
||||
while (!console);
|
||||
console.log(a);
|
||||
})(42);
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
reduce_iife_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -587,3 +627,54 @@ issue_4401: {
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4448: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var A;
|
||||
try {
|
||||
(arguments => {
|
||||
arguments[0];
|
||||
})(A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var A;
|
||||
try {
|
||||
(arguments => {
|
||||
arguments[0];
|
||||
})(A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4476: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
(function(a, b) {
|
||||
(a => {
|
||||
console.log(arguments[0], a);
|
||||
})(b);
|
||||
})("foo", "bar");
|
||||
}
|
||||
expect: {
|
||||
(function(a, b) {
|
||||
(a => {
|
||||
console.log(arguments[0], a);
|
||||
})(b);
|
||||
})("foo", "bar");
|
||||
}
|
||||
expect_stdout: "foo bar"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -461,3 +461,17 @@ issue_3949_2: {
|
||||
}
|
||||
expect_stdout: "100"
|
||||
}
|
||||
|
||||
issue_4521: {
|
||||
options = {
|
||||
assignments: true,
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
var a = (a = 42 | a) ? console.log(a) : 0;
|
||||
}
|
||||
expect: {
|
||||
var a = (a |= 42) ? console.log(a) : 0;
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -1,642 +0,0 @@
|
||||
await_await: {
|
||||
input: {
|
||||
(async function() {
|
||||
console.log("PASS");
|
||||
await await 42;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log("PASS");
|
||||
await await 42;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
defun_name: {
|
||||
input: {
|
||||
async function await() {
|
||||
console.log("PASS");
|
||||
}
|
||||
await();
|
||||
}
|
||||
expect: {
|
||||
async function await() {
|
||||
console.log("PASS");
|
||||
}
|
||||
await();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
nested_await: {
|
||||
input: {
|
||||
(async function() {
|
||||
console.log(function(await) {
|
||||
return await;
|
||||
}("PASS"));
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log(function(await) {
|
||||
return await;
|
||||
}("PASS"));
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
reduce_single_use_defun: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
async function f(a) {
|
||||
console.log(a);
|
||||
}
|
||||
f("PASS");
|
||||
}
|
||||
expect: {
|
||||
(async function(a) {
|
||||
console.log(a);
|
||||
})("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
dont_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
(async function() {
|
||||
A;
|
||||
})().catch(function() {});
|
||||
console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
A;
|
||||
})().catch(function() {});
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = async function() {}();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
var a = async function() {}();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
negate: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console && async function() {} && console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
console && async function() {} && console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
negate_iife: {
|
||||
options = {
|
||||
negate_iife: true,
|
||||
}
|
||||
input: {
|
||||
(async function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
!async function() {
|
||||
console.log("PASS");
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_function: {
|
||||
options = {
|
||||
properties: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
async f() {
|
||||
console.log("PASS");
|
||||
},
|
||||
}).f();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
collapse_vars_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
a = "PASS";
|
||||
await 42;
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
a = "PASS";
|
||||
await 42;
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
collapse_vars_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
await (a = "PASS");
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
await (a = "PASS");
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
collapse_vars_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
await (a = "PASS", 42);
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(async function() {
|
||||
await (a = "PASS", 42);
|
||||
return "PASS";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4335_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
var await = "PASS";
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
return await;
|
||||
}());
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var await = "PASS";
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
return await;
|
||||
}());
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4335_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
function await() {}
|
||||
return "PASS";
|
||||
}());
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
function await() {}
|
||||
return "PASS";
|
||||
}());
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4337: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
a();
|
||||
})(async function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
(async function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4340: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
(async function a(a) {
|
||||
console.log(a || "PASS");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function a(a) {
|
||||
console.log(a || "PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
call_expression: {
|
||||
input: {
|
||||
console.log(typeof async function(log) {
|
||||
(await log)("FAIL");
|
||||
}(console.log).then);
|
||||
}
|
||||
expect_exact: 'console.log(typeof async function(log){(await log)("FAIL")}(console.log).then);'
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
property_access_expression: {
|
||||
input: {
|
||||
console.log(typeof async function(con) {
|
||||
(await con).log("FAIL");
|
||||
}(console).then);
|
||||
}
|
||||
expect_exact: 'console.log(typeof async function(con){(await con).log("FAIL")}(console).then);'
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
reduce_iife_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(async function(a) {
|
||||
console.log(a + a);
|
||||
})(21);
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log(42);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
reduce_iife_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 21;
|
||||
(async function() {
|
||||
console.log(a + a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log(42);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
reduce_iife_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo";
|
||||
(async function() {
|
||||
console.log(a);
|
||||
console.log(await a);
|
||||
})();
|
||||
a = "bar";
|
||||
}
|
||||
expect: {
|
||||
var a = "foo";
|
||||
(async function() {
|
||||
console.log(a);
|
||||
console.log(await a);
|
||||
})();
|
||||
a = "bar";
|
||||
}
|
||||
expect_stdout: "foo"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4347_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo";
|
||||
f();
|
||||
a = "bar";
|
||||
f();
|
||||
async function f() {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "foo";
|
||||
f();
|
||||
a = "bar";
|
||||
f();
|
||||
async function f() {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4347_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
(async function() {
|
||||
throw 42;
|
||||
a = "FAIL";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
(async function() {
|
||||
throw 42;
|
||||
a = "FAIL";
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4349_1: {
|
||||
input: {
|
||||
console.log(typeof async function() {
|
||||
await /abc/;
|
||||
}().then);
|
||||
}
|
||||
expect_exact: "console.log(typeof async function(){await/abc/}().then);"
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4349_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof async function() {
|
||||
(function(a) {
|
||||
this[a];
|
||||
}(await 0));
|
||||
}().then);
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof async function() {
|
||||
(function(a) {
|
||||
this[a];
|
||||
}(await 0));
|
||||
}().then);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4349_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function(await) {
|
||||
return async function(a) {
|
||||
this[a];
|
||||
}(await);
|
||||
}(this).then);
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function(await) {
|
||||
return async function(a) {
|
||||
this[a];
|
||||
}(await);
|
||||
}(this).then);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4359: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(async function(a) {
|
||||
return a;
|
||||
})(A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(async function(a) {
|
||||
return a;
|
||||
})(A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4377: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
return function() {
|
||||
f;
|
||||
async function f() {}
|
||||
return f();
|
||||
}();
|
||||
}().then);
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
return f();
|
||||
async function f() {}
|
||||
}().then);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4406: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
A = "PASS";
|
||||
B = "FAIL";
|
||||
(function() {
|
||||
var a, b;
|
||||
a = A;
|
||||
(async function({
|
||||
[console.log(a)]: {},
|
||||
}) {})((b = B) && { undefined: b });
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
A = "PASS";
|
||||
B = "FAIL";
|
||||
(function() {
|
||||
var a, b;
|
||||
a = A;
|
||||
(async function({
|
||||
[console.log(a)]: {},
|
||||
}) {})((b = B) && { undefined: b });
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4417: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
return await => 0;
|
||||
}().prototype);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(async function() {
|
||||
console.log(function() {
|
||||
return await => 0;
|
||||
}().prototype);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=8"
|
||||
}
|
||||
1220
test/compress/awaits.js
Normal file
1220
test/compress/awaits.js
Normal file
File diff suppressed because it is too large
Load Diff
62
test/compress/bigint.js
Normal file
62
test/compress/bigint.js
Normal file
@@ -0,0 +1,62 @@
|
||||
arithmetic: {
|
||||
input: {
|
||||
console.log(((1n + 0x2n) * (0o3n - -4n)) >> (5n - 6n));
|
||||
}
|
||||
expect_exact: "console.log((1n+0x2n)*(0o3n- -4n)>>5n-6n);"
|
||||
expect_stdout: "42n"
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
minus_dot: {
|
||||
input: {
|
||||
console.log(typeof -42n.toString(), typeof (-42n).toString());
|
||||
}
|
||||
expect_exact: "console.log(typeof-42n.toString(),typeof(-42n).toString());"
|
||||
expect_stdout: "number string"
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log((0xDEAD_BEEFn).toString(16));
|
||||
}
|
||||
expect: {
|
||||
console.log(0xdeadbeefn.toString(16));
|
||||
}
|
||||
expect_stdout: "deadbeef"
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
Number: {
|
||||
options = {
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(Number(-0xfeed_dead_beef_badn));
|
||||
}
|
||||
expect: {
|
||||
console.log(+("" + -0xfeed_dead_beef_badn));
|
||||
}
|
||||
expect_stdout: "-1148098955808013200"
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
issue_4590: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
A = 1;
|
||||
0n || console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
A = 1;
|
||||
0n || console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=10"
|
||||
}
|
||||
@@ -3145,8 +3145,8 @@ issue_2313_2: {
|
||||
var c = 0;
|
||||
!function a() {
|
||||
a && c++;
|
||||
var a = 0;
|
||||
a && c++;
|
||||
var a;
|
||||
(a = 0) && c++;
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
@@ -4273,8 +4273,8 @@ issue_2436_14: {
|
||||
var b = {};
|
||||
(function() {
|
||||
a && function(c, d) {
|
||||
console.log(c, d);
|
||||
}(b, a);
|
||||
console.log(b, d);
|
||||
}(0, a);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -5502,8 +5502,7 @@ collapse_rhs_lhs_2: {
|
||||
expect: {
|
||||
var b = 1;
|
||||
(function f(f) {
|
||||
f = b;
|
||||
f[b] = 0;
|
||||
b[b] = 0;
|
||||
})();
|
||||
console.log("PASS");
|
||||
}
|
||||
@@ -5609,6 +5608,7 @@ collapse_rhs_array: {
|
||||
collapse_rhs_boolean_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
@@ -5634,6 +5634,7 @@ collapse_rhs_boolean_1: {
|
||||
collapse_rhs_boolean_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
@@ -5668,6 +5669,7 @@ collapse_rhs_boolean_3: {
|
||||
booleans: true,
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a, f, g, h, i, n, s, t, x, y;
|
||||
@@ -5721,6 +5723,7 @@ collapse_rhs_function: {
|
||||
collapse_rhs_number: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
@@ -5800,6 +5803,7 @@ collapse_rhs_regexp: {
|
||||
collapse_rhs_string: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
@@ -5996,7 +6000,7 @@ issue_3215_1: {
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof 42);
|
||||
console.log("number");
|
||||
}
|
||||
expect_stdout: "number"
|
||||
}
|
||||
@@ -8662,3 +8666,92 @@ issue_4430_2: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
collapse_and_assign: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var log = console.log;
|
||||
var a = {
|
||||
p: "PASS",
|
||||
};
|
||||
console && (a = a.p);
|
||||
log(a);
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
var a = {
|
||||
p: "PASS",
|
||||
};
|
||||
log(a = console ? a.p : a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
collapse_or_assign: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var log = console.log;
|
||||
var a = {
|
||||
p: "PASS",
|
||||
};
|
||||
a.q || (a = a.p);
|
||||
log(a);
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
var a = {
|
||||
p: "PASS",
|
||||
};
|
||||
log(a = !a.q ? a.p : a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4586_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 42;
|
||||
(function f(b) {
|
||||
var b = a;
|
||||
if (b === arguments[0])
|
||||
console.log("PASS");
|
||||
})(console);
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
(function f(b) {
|
||||
var b = a;
|
||||
if (b === arguments[0])
|
||||
console.log("PASS");
|
||||
})(console);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4586_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 42;
|
||||
(function f(b) {
|
||||
b = a;
|
||||
if (b === arguments[0])
|
||||
console.log("PASS");
|
||||
})(console);
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
(function f(b) {
|
||||
if ((b = a) === arguments[0])
|
||||
console.log("PASS");
|
||||
})(console);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -658,6 +658,30 @@ legacy_scope: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
hoist_vars: {
|
||||
options = {
|
||||
hoist_vars: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const a = "FAIL";
|
||||
var b = 42;
|
||||
}
|
||||
var a = "PASS";
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var b;
|
||||
{
|
||||
const a = "FAIL";
|
||||
b = 42;
|
||||
}
|
||||
var a = "PASS";
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4191: {
|
||||
options = {
|
||||
functions: true,
|
||||
@@ -1375,3 +1399,38 @@ issue_4365_2: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4527: {
|
||||
mangle = {}
|
||||
input: {
|
||||
(function() {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (a) {
|
||||
try {
|
||||
const a = FAIL;
|
||||
} finally {
|
||||
if (!b)
|
||||
return console.log("aaaa");
|
||||
}
|
||||
}
|
||||
var b;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (a) {
|
||||
try {
|
||||
const a = FAIL;
|
||||
} finally {
|
||||
if (!t)
|
||||
return console.log("aaaa");
|
||||
}
|
||||
}
|
||||
var t;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "aaaa"
|
||||
}
|
||||
|
||||
@@ -725,7 +725,7 @@ issue_2749: {
|
||||
expect: {
|
||||
var a = 2, c = "PASS";
|
||||
while (a--)
|
||||
b = void 0, b ? c = "FAIL" : b = 1;
|
||||
b = void 0, b ? c = "FAIL" : 1;
|
||||
var b;
|
||||
console.log(c);
|
||||
}
|
||||
@@ -1399,3 +1399,21 @@ issue_4366: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4570: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
var a = function(b) {
|
||||
return a += b;
|
||||
}() ? 0 : a;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = (a += void 0) ? 0 : a;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
1663
test/compress/default-values.js
Normal file
1663
test/compress/default-values.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ redefine_arguments_2: {
|
||||
|
||||
redefine_arguments_3: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -188,7 +188,7 @@ funarg_side_effects_1: {
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function({}) {})();
|
||||
[ {} ] = [];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
@@ -259,7 +259,7 @@ funarg_side_effects_3: {
|
||||
|
||||
funarg_unused_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -318,7 +318,7 @@ funarg_unused_3: {
|
||||
|
||||
funarg_unused_4: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
@@ -384,7 +384,7 @@ funarg_unused_6_inline: {
|
||||
|
||||
funarg_unused_6_keep_fargs: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -426,7 +426,7 @@ funarg_collapse_vars_1: {
|
||||
funarg_collapse_vars_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -505,7 +505,7 @@ funarg_reduce_vars_1: {
|
||||
funarg_reduce_vars_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
@@ -682,7 +682,7 @@ funarg_inline: {
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function({}) {})();
|
||||
[ {} ] = [];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
@@ -691,6 +691,28 @@ funarg_inline: {
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
process_boolean_returns: {
|
||||
options = {
|
||||
booleans: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function({ length }) {
|
||||
return length ? "FAIL" : "PASS";
|
||||
}(function() {
|
||||
return 42;
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function({ length }) {
|
||||
return length ? "FAIL" : "PASS";
|
||||
}(function() {
|
||||
return 42;
|
||||
}));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
simple_const: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -1101,7 +1123,7 @@ join_vars: {
|
||||
|
||||
keep_fargs: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1336,6 +1358,24 @@ fn_name_unused: {
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
hoist_vars: {
|
||||
options = {
|
||||
hoist_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
var [ b ] = [ 42 ];
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
var [ b ] = [ 42 ];
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4280: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -1678,10 +1718,14 @@ issue_4312: {
|
||||
expect: {
|
||||
var a;
|
||||
b = "PASS",
|
||||
(function({
|
||||
[a = b]: d,
|
||||
}){})((c = "FAIL") && c);
|
||||
var b, c;
|
||||
c = "FAIL",
|
||||
[
|
||||
{
|
||||
[a = b]: d,
|
||||
},
|
||||
] = [ c && c ],
|
||||
void 0;
|
||||
var b, c, d;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -1743,9 +1787,7 @@ issue_4319: {
|
||||
function f(a) {
|
||||
while (!a);
|
||||
}
|
||||
console.log(function({}) {
|
||||
return f(console);
|
||||
}(0));
|
||||
console.log(([ {} ] = [ 0 ], f(console)));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=6"
|
||||
@@ -1754,7 +1796,7 @@ issue_4319: {
|
||||
issue_4321: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
@@ -1769,11 +1811,9 @@ issue_4321: {
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
console.log(function({}) {
|
||||
return function() {
|
||||
while (!console);
|
||||
}();
|
||||
}());
|
||||
console.log(([ {} ] = [], function() {
|
||||
while (!console);
|
||||
}()));
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
@@ -1804,11 +1844,15 @@ issue_4323: {
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
(function({
|
||||
[function a() {
|
||||
console.log(typeof a);
|
||||
}()]: d,
|
||||
}) {})(0);
|
||||
[
|
||||
{
|
||||
[function a() {
|
||||
console.log(typeof a);
|
||||
}()]: d,
|
||||
},
|
||||
] = [ 0 ],
|
||||
void 0;
|
||||
var d;
|
||||
e = 1,
|
||||
console.log,
|
||||
void e.p;
|
||||
@@ -2037,3 +2081,478 @@ issue_4425: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4436_Infinity: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function({
|
||||
[delete Infinity]: a,
|
||||
}) {
|
||||
var Infinity;
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function({
|
||||
[delete Infinity]: a,
|
||||
}) {
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4436_NaN: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function({
|
||||
[delete NaN]: a,
|
||||
}) {
|
||||
var NaN;
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function({
|
||||
[delete NaN]: a,
|
||||
}) {
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4436_undefined: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function({
|
||||
[delete undefined]: a,
|
||||
}) {
|
||||
var undefined;
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function({
|
||||
[delete undefined]: a,
|
||||
}) {
|
||||
return a;
|
||||
}({
|
||||
true: "FAIL",
|
||||
false: "PASS",
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4446: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
a = "PASS";
|
||||
var a = [ a[0] ] = [ a ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect: {
|
||||
a = "PASS";
|
||||
var a = [ a[0] ] = [ a ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4456: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
set p(v) {
|
||||
console.log(v);
|
||||
},
|
||||
};
|
||||
[ function() {
|
||||
try {
|
||||
return o;
|
||||
} catch ({}) {}
|
||||
}().p ] = [ "PASS" ];
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
set p(v) {
|
||||
console.log(v);
|
||||
},
|
||||
};
|
||||
[ function() {
|
||||
try {
|
||||
return o;
|
||||
} catch ({}) {}
|
||||
}().p ] = [ "PASS" ];
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4485_1: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function([]) {
|
||||
var arguments;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function([]) {
|
||||
var arguments;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4485_2: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(function([]) {
|
||||
var arguments = null;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function([]) {
|
||||
var arguments = null;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4485_3: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function([]) {
|
||||
var arguments;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function([]) {
|
||||
var arguments;
|
||||
try {
|
||||
arguments.length;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4500: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fnames: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f(b) {
|
||||
return [ b ] = [], b;
|
||||
}("FAIL");
|
||||
console.log(a || "PASS");
|
||||
}
|
||||
expect: {
|
||||
var a = function f(b) {
|
||||
return [ b ] = [], b;
|
||||
}("FAIL");
|
||||
console.log(a || "PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4504: {
|
||||
options = {
|
||||
inline: true,
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
A = "FAIL";
|
||||
(function f(a) {
|
||||
({
|
||||
[console.log(a)]: 0[(b => console + b)(A)]
|
||||
} = 0);
|
||||
})("PASS");
|
||||
}
|
||||
expect: {
|
||||
A = "FAIL";
|
||||
(function f(a) {
|
||||
({
|
||||
[console.log(a)]: 0[b = A, console + b]
|
||||
} = 0);
|
||||
var b;
|
||||
})("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4508: {
|
||||
options = {
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
for (var i = 0; i < 2; i++)
|
||||
(function f([ a ]) {
|
||||
var a = console.log(a) && b, b = null;
|
||||
})([ "PASS" ]);
|
||||
}
|
||||
expect: {
|
||||
for (var i = 0; i < 2; i++)
|
||||
[ [ a ] ] = [ [ "PASS" ] ],
|
||||
b = void 0,
|
||||
a = console.log(a) && b,
|
||||
b = null,
|
||||
void 0;
|
||||
var a, b;
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4512: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function([ a, b = a ]) {}([]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function([ a, b = a ]) {}([]));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4519_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function() {
|
||||
var [ arguments ] = [];
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function() {
|
||||
var [ arguments ] = [];
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4519_2: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function() {
|
||||
var [ arguments ] = [];
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function() {
|
||||
var [ arguments ] = [];
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4554: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
A = "PASS";
|
||||
var a = "FAIL";
|
||||
try {
|
||||
(function({}, b) {
|
||||
return b;
|
||||
})(void 0, a = A);
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
A = "PASS";
|
||||
var a = "FAIL";
|
||||
try {
|
||||
(function({}, b) {
|
||||
return b;
|
||||
})(void 0, a = A);
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4584: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function f({
|
||||
[console.log(a = "FAIL")]: a,
|
||||
}) {})(0);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function f({
|
||||
[console.log(a = "FAIL")]: a,
|
||||
}) {})(0);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4608_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
[ arguments ] = [ "foo" ];
|
||||
console.log(arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
[ arguments ] = [ "foo" ];
|
||||
console.log(arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "f"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4608_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
[ arguments ] = [ "foo" ];
|
||||
console.log(arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
[ arguments ] = [ "foo" ];
|
||||
console.log(arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "f"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -4,15 +4,16 @@ unused_funarg_1: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c, d, e) {
|
||||
console.log(function f(a, b, c, d, e) {
|
||||
return a + b;
|
||||
}
|
||||
}(14, 28));
|
||||
}
|
||||
expect: {
|
||||
function f(a, b) {
|
||||
console.log(function(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
}(14, 28));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
unused_funarg_2: {
|
||||
@@ -21,15 +22,16 @@ unused_funarg_2: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c, d, e) {
|
||||
console.log(function f(a, b, c, d, e) {
|
||||
return a + c;
|
||||
}
|
||||
}(14, 21, 28));
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c) {
|
||||
console.log(function(a, c) {
|
||||
return a + c;
|
||||
}
|
||||
}(14, 28));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
unused_nested_function: {
|
||||
@@ -357,37 +359,6 @@ drop_toplevel_vars: {
|
||||
}
|
||||
}
|
||||
|
||||
drop_toplevel_vars_fargs: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
toplevel: "vars",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a, b = 1, c = g;
|
||||
function f(d) {
|
||||
return function() {
|
||||
c = 2;
|
||||
};
|
||||
}
|
||||
a = 2;
|
||||
function g() {}
|
||||
function h() {}
|
||||
console.log(b = 3);
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return function() {
|
||||
2;
|
||||
};
|
||||
}
|
||||
2;
|
||||
function g() {}
|
||||
function h() {}
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
|
||||
drop_toplevel_all: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
@@ -625,13 +596,14 @@ drop_fargs: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
console.log(function f(a) {
|
||||
var b = a;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
function f() {}
|
||||
console.log(function() {}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
drop_fnames: {
|
||||
@@ -2027,7 +1999,7 @@ issue_3192_1: {
|
||||
|
||||
issue_3192_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -2166,6 +2138,7 @@ issue_3497: {
|
||||
issue_3515_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -2217,6 +2190,7 @@ issue_3515_2: {
|
||||
issue_3515_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -2284,6 +2258,7 @@ function_assign: {
|
||||
issue_3598: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -2435,7 +2410,7 @@ issue_3673: {
|
||||
|
||||
issue_3746: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -2697,8 +2672,7 @@ issue_3956: {
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var c, d;
|
||||
c += 0,
|
||||
var d;
|
||||
console.log(NaN),
|
||||
d = 1 ^ console.log(1),
|
||||
console.log(d);
|
||||
@@ -2713,7 +2687,7 @@ issue_3956: {
|
||||
issue_3962_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -2731,13 +2705,13 @@ issue_3962_1: {
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = (function(c) {
|
||||
(function(c) {
|
||||
do {
|
||||
console;
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}(1), 0);
|
||||
})(1);
|
||||
void 0;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -2745,7 +2719,7 @@ issue_3962_1: {
|
||||
|
||||
issue_3962_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
@@ -2764,13 +2738,13 @@ issue_3962_2: {
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
a = (function(c) {
|
||||
(function(c) {
|
||||
do {
|
||||
console;
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}(1), 0);
|
||||
})(1);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -2827,7 +2801,9 @@ issue_4017: {
|
||||
var a = 0;
|
||||
console.log(function() {
|
||||
c &= 0;
|
||||
var c = (a++, A = a, 0);
|
||||
var c;
|
||||
a++,
|
||||
A = a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
@@ -2948,7 +2924,7 @@ issue_4133: {
|
||||
|
||||
issue_4144: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -3153,3 +3129,125 @@ issue_4413: {
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4464_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var a = function() {};
|
||||
return [ arguments, a ];
|
||||
}
|
||||
console.log(typeof f()[1]);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
a = function() {};
|
||||
return [ arguments, a ];
|
||||
}
|
||||
console.log(typeof f()[1]);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4464_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var a = function() {};
|
||||
return [ arguments, a ];
|
||||
}
|
||||
console.log(typeof f(42)[0][0]);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
a = function() {};
|
||||
return [ arguments, a ];
|
||||
}
|
||||
console.log(typeof f(42)[0][0]);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4464_3: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function a(a) {
|
||||
var a = function() {};
|
||||
return [ arguments[0], a ];
|
||||
})(42).forEach(function(b) {
|
||||
console.log(typeof b);
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
a = function() {};
|
||||
return [ arguments[0], a ];
|
||||
})(42).forEach(function(b) {
|
||||
console.log(typeof b);
|
||||
});
|
||||
}
|
||||
expect_stdout: [
|
||||
"function",
|
||||
"function",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4558_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
pure_getters: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
var b = 1, b = c >>>= a;
|
||||
var c = 0;
|
||||
b && 0[a++],
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
var b = c >>>= a;
|
||||
var c;
|
||||
b && a++,
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4558_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = 1;
|
||||
var b = (a = NaN) || (console.log("PASS"), 2);
|
||||
return a;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
(a = NaN) || console.log("PASS");
|
||||
return a;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -703,6 +703,7 @@ prototype_function: {
|
||||
var g = 0();
|
||||
var h = 0();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
call_args: {
|
||||
@@ -2800,7 +2801,7 @@ operator_in: {
|
||||
console.log("PASS" in { });
|
||||
console.log("FAIL" in { });
|
||||
console.log("toString" in { });
|
||||
console.log(true);
|
||||
console.log("toString" in { toString: 3 });
|
||||
}
|
||||
expect_stdout: [
|
||||
"true",
|
||||
@@ -3117,3 +3118,61 @@ issue_4422: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4480: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f(b) {
|
||||
b = "FAIL";
|
||||
arguments[0] = "PASS";
|
||||
var arguments = 0;
|
||||
console.log(b);
|
||||
}(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function(b) {
|
||||
b = "FAIL";
|
||||
arguments[0] = "PASS";
|
||||
var arguments = 0;
|
||||
console.log(b);
|
||||
}(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4552: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fnames: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f(b) {
|
||||
return function() {
|
||||
b++;
|
||||
try {
|
||||
return b;
|
||||
} catch (e) {}
|
||||
}();
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = function f(b) {
|
||||
return function() {
|
||||
b++;
|
||||
try {
|
||||
return b;
|
||||
} catch (e) {}
|
||||
}();
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
58
test/compress/exponentiation.js
Normal file
58
test/compress/exponentiation.js
Normal file
@@ -0,0 +1,58 @@
|
||||
precedence_1: {
|
||||
input: {
|
||||
console.log(-4 ** 3 ** 2);
|
||||
}
|
||||
expect_exact: "console.log((-4)**3**2);"
|
||||
expect_stdout: "-262144"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
precedence_2: {
|
||||
input: {
|
||||
console.log(-4 ** (3 ** 2));
|
||||
}
|
||||
expect_exact: "console.log((-4)**3**2);"
|
||||
expect_stdout: "-262144"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
precedence_3: {
|
||||
input: {
|
||||
console.log(-(4 ** 3) ** 2);
|
||||
}
|
||||
expect_exact: "console.log((-(4**3))**2);"
|
||||
expect_stdout: "4096"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
precedence_4: {
|
||||
input: {
|
||||
console.log((-4 ** 3) ** 2);
|
||||
}
|
||||
expect_exact: "console.log(((-4)**3)**2);"
|
||||
expect_stdout: "4096"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
await: {
|
||||
input: {
|
||||
(async a => a * await a ** ++a % a)(2).then(console.log);
|
||||
}
|
||||
expect_exact: "(async a=>a*(await a)**++a%a)(2).then(console.log);"
|
||||
expect_stdout: "1"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(1 + 2 ** 3 - 4);
|
||||
}
|
||||
expect: {
|
||||
console.log(5);
|
||||
}
|
||||
expect_stdout: "5"
|
||||
node_version: ">=8"
|
||||
}
|
||||
@@ -229,7 +229,7 @@ issue_203: {
|
||||
}
|
||||
expect: {
|
||||
var m = {};
|
||||
var fn = Function("n,o", "o.exports=42");
|
||||
var fn = Function("n,o,t", "o.exports=42");
|
||||
fn(null, m, m.exports);
|
||||
console.log(m.exports);
|
||||
}
|
||||
@@ -2175,7 +2175,7 @@ issue_3016_3: {
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
console.log((a = void 0, a ? "FAIL" : "PASS"));
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
@@ -2208,7 +2208,7 @@ issue_3016_3_ie8: {
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
console.log((a = void 0, a ? "FAIL" : "PASS"));
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
@@ -4230,7 +4230,7 @@ substitute: {
|
||||
substitute_add_farg: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
function f(g) {
|
||||
@@ -4411,7 +4411,9 @@ substitute_drop_farg: {
|
||||
return f;
|
||||
},
|
||||
function() {
|
||||
return f;
|
||||
return function(d, e) {
|
||||
return f(d, e);
|
||||
};
|
||||
},
|
||||
].forEach(function(g) {
|
||||
console.log(g()(o), g().call(o, o));
|
||||
@@ -4594,7 +4596,7 @@ substitute_use_strict: {
|
||||
issue_3833: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -4751,7 +4753,7 @@ issue_4006: {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
@@ -5132,8 +5134,8 @@ issue_4259: {
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
for (a in a);
|
||||
var a = function b() {
|
||||
for (b in b);
|
||||
}
|
||||
a();
|
||||
console.log(typeof a);
|
||||
@@ -5223,3 +5225,185 @@ trailing_comma: {
|
||||
expect_exact: 'new function(a,b){console.log(b,a)}(42,"PASS");'
|
||||
expect_stdout: "PASS 42"
|
||||
}
|
||||
|
||||
issue_4451: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f() {
|
||||
for (f in "foo")
|
||||
return f;
|
||||
};
|
||||
while (console.log(typeof a()));
|
||||
}
|
||||
expect: {
|
||||
var a = function f() {
|
||||
for (f in "foo")
|
||||
return f;
|
||||
};
|
||||
while (console.log(typeof a()));
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4471: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
f(f());
|
||||
function f() {
|
||||
return g();
|
||||
}
|
||||
function g() {
|
||||
{
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
f(g());
|
||||
function f() {
|
||||
return g();
|
||||
}
|
||||
function g() {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4612_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function f() {
|
||||
return g();
|
||||
}
|
||||
function g(a) {
|
||||
return a || f();
|
||||
}
|
||||
return g("PASS");
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4612_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function fn() {
|
||||
return h();
|
||||
}
|
||||
function g() {
|
||||
return fn();
|
||||
}
|
||||
function h(a) {
|
||||
return a || fn();
|
||||
}
|
||||
return h("PASS");
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4612_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
return g();
|
||||
function f() {
|
||||
return g;
|
||||
}
|
||||
function g() {
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
return g();
|
||||
function f() {
|
||||
return g;
|
||||
}
|
||||
function g() {
|
||||
return f;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4612_4: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function f() {
|
||||
return h();
|
||||
}
|
||||
function g() {
|
||||
{
|
||||
return h();
|
||||
}
|
||||
}
|
||||
function h() {
|
||||
{
|
||||
return g();
|
||||
}
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
function f() {
|
||||
return h();
|
||||
}
|
||||
function g() {
|
||||
return h();
|
||||
}
|
||||
function h() {
|
||||
return g();
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -89,6 +89,31 @@ sequences_funs: {
|
||||
}
|
||||
}
|
||||
|
||||
catch_var: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
hoist_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
a;
|
||||
} catch (a) {
|
||||
var a = 0;
|
||||
a;
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2295: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -109,3 +134,76 @@ issue_2295: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_4487: {
|
||||
options = {
|
||||
functions: true,
|
||||
hoist_vars: true,
|
||||
keep_fnames: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function f() {
|
||||
var f = console.log(typeof f);
|
||||
};
|
||||
var b = a();
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
var a = console.log(typeof a);
|
||||
}
|
||||
a();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4489: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
hoist_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
A = 0;
|
||||
var o = !0 || null;
|
||||
for (var k in o);
|
||||
console.log(k);
|
||||
}
|
||||
expect: {
|
||||
!(A = 0);
|
||||
for (var k in true);
|
||||
console.log(k);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4517: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
hoist_vars: true,
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var a = 2;
|
||||
A = a;
|
||||
var b = typeof !1;
|
||||
return A + b;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a = 2;
|
||||
A = a;
|
||||
return A + typeof !1;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "2boolean"
|
||||
}
|
||||
|
||||
@@ -2900,3 +2900,22 @@ issue_4250: {
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4568: {
|
||||
options = {
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof f, function(a) {
|
||||
return a.length;
|
||||
}([ function f() {} ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof f, function(a) {
|
||||
return a.length;
|
||||
}([ function f() {} ]));
|
||||
}
|
||||
expect_stdout: "undefined 1"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ issue_269_1: {
|
||||
expect: {
|
||||
var x = {};
|
||||
console.log(
|
||||
x + "", +x, !!x,
|
||||
"" + x, +("" + x), !!x,
|
||||
"", 0, false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,42 +63,81 @@ eval_unused: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f1(a, eval, c, d, e) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
function o(k) {
|
||||
return { c: 14 }[k];
|
||||
}
|
||||
console.log(function f1(a, eval, c, d, e) {
|
||||
return a("c") + eval;
|
||||
}(o, 28, true));
|
||||
console.log(function f2(a, b, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(14, true, 28));
|
||||
console.log(function f3(a, eval, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(28, o, true));
|
||||
}
|
||||
expect: {
|
||||
function f1(a, eval) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
function o(k) {
|
||||
return { c: 14 }[k];
|
||||
}
|
||||
console.log(function(a, eval) {
|
||||
return a("c") + eval;
|
||||
}(o, 28));
|
||||
console.log(function f2(a, b, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(14, true, 28));
|
||||
console.log(function f3(a, eval, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(28, o, true));
|
||||
}
|
||||
expect_stdout: [
|
||||
"42",
|
||||
"42",
|
||||
"42",
|
||||
]
|
||||
}
|
||||
|
||||
eval_mangle: {
|
||||
mangle = {
|
||||
};
|
||||
input: {
|
||||
function f1(a, eval, c, d, e) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
mangle = {}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
expect_exact: 'function f1(n,c,e,a,f){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}'
|
||||
input: {
|
||||
function o(k) {
|
||||
return { cc: 14 }[k + "c"];
|
||||
}
|
||||
console.log(function f1(a, eval, c, d, e) {
|
||||
return a("c") + eval;
|
||||
}(o, 28, true));
|
||||
console.log(function f2(a, b, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(14, true, 28));
|
||||
console.log(function f3(a, eval, c, d, e) {
|
||||
return a + eval("c");
|
||||
}(28, o, true));
|
||||
}
|
||||
expect_exact: [
|
||||
"function o(o) {",
|
||||
" return {",
|
||||
" cc: 14",
|
||||
' }[o + "c"];',
|
||||
"}",
|
||||
"",
|
||||
"console.log(function o(c, e, n, r, t) {",
|
||||
' return c("c") + e;',
|
||||
"}(o, 28, true));",
|
||||
"",
|
||||
"console.log(function f2(a, b, c, d, e) {",
|
||||
' return a + eval("c");',
|
||||
"}(14, true, 28));",
|
||||
"",
|
||||
"console.log(function f3(a, eval, c, d, e) {",
|
||||
' return a + eval("c");',
|
||||
"}(28, o, true));",
|
||||
]
|
||||
expect_stdout: [
|
||||
"42",
|
||||
"42",
|
||||
"42",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -790,7 +790,7 @@ issue_3795: {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
|
||||
@@ -18,43 +18,6 @@ keep_fargs_false: {
|
||||
function j(e) {}
|
||||
console.log(h(), i().length, j.length);
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
return f.length;
|
||||
}(), function g() {
|
||||
return g;
|
||||
}().length);
|
||||
function h() {
|
||||
return h.length;
|
||||
}
|
||||
function i() {
|
||||
return i;
|
||||
}
|
||||
function j() {}
|
||||
console.log(h(), i().length, j.length);
|
||||
}
|
||||
}
|
||||
|
||||
keep_fargs_strict: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a) {
|
||||
return f.length;
|
||||
}(), function g(b) {
|
||||
return g;
|
||||
}().length);
|
||||
function h(c) {
|
||||
return h.length;
|
||||
}
|
||||
function i(d) {
|
||||
return i;
|
||||
}
|
||||
function j(e) {}
|
||||
console.log(h(), i().length, j.length);
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a) {
|
||||
return f.length;
|
||||
@@ -117,61 +80,11 @@ keep_fargs_true: {
|
||||
]
|
||||
}
|
||||
|
||||
replace_index: {
|
||||
options = {
|
||||
arguments: true,
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
properties: true,
|
||||
}
|
||||
input: {
|
||||
var arguments = [];
|
||||
console.log(arguments[0]);
|
||||
(function() {
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
(function(a, b) {
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
(function(arguments) {
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
(function() {
|
||||
var arguments;
|
||||
console.log(arguments[1], arguments["1"], arguments["foo"]);
|
||||
})("bar", 42);
|
||||
}
|
||||
expect: {
|
||||
var arguments = [];
|
||||
console.log(arguments[0]);
|
||||
(function(argument_0, argument_1) {
|
||||
console.log(argument_1, argument_1, arguments.foo);
|
||||
})("bar", 42);
|
||||
(function(a, b) {
|
||||
console.log(b, b, arguments.foo);
|
||||
})("bar", 42);
|
||||
(function(arguments) {
|
||||
console.log(arguments[1], arguments[1], arguments.foo);
|
||||
})("bar", 42);
|
||||
(function() {
|
||||
var arguments;
|
||||
console.log(arguments[1], arguments[1], arguments.foo);
|
||||
})("bar", 42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"42 42 undefined",
|
||||
"42 42 undefined",
|
||||
"a a undefined",
|
||||
"42 42 undefined",
|
||||
]
|
||||
}
|
||||
|
||||
replace_index_strict: {
|
||||
options = {
|
||||
arguments: true,
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
properties: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
@@ -202,7 +115,7 @@ replace_index_strict: {
|
||||
issue_1858: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
pure_getters: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -224,7 +137,7 @@ issue_1858: {
|
||||
issue_2187_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -245,7 +158,7 @@ issue_2187_2: {
|
||||
issue_2203_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -280,7 +193,7 @@ issue_2203_2: {
|
||||
issue_2298: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -323,7 +236,7 @@ issue_2298: {
|
||||
issue_2319_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -346,7 +259,7 @@ issue_2319_1: {
|
||||
issue_2319_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -371,7 +284,7 @@ issue_2319_2: {
|
||||
issue_2319_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -396,7 +309,7 @@ issue_2319_3: {
|
||||
issue_2425_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -419,7 +332,7 @@ issue_2425_1: {
|
||||
issue_2425_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -442,7 +355,7 @@ issue_2425_2: {
|
||||
issue_2425_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -465,7 +378,7 @@ issue_2425_3: {
|
||||
issue_2436_13: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -499,7 +412,7 @@ issue_2436_13: {
|
||||
issue_2506: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -538,7 +451,7 @@ issue_2506: {
|
||||
|
||||
issue_2226_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -585,7 +498,7 @@ issue_2226_1: {
|
||||
issue_2226_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
@@ -607,7 +520,7 @@ issue_2226_2: {
|
||||
issue_2226_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -627,7 +540,7 @@ issue_2226_3: {
|
||||
|
||||
issue_3192: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -657,7 +570,7 @@ issue_3192: {
|
||||
if_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -679,7 +592,7 @@ if_increment: {
|
||||
try_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -703,7 +616,7 @@ try_increment: {
|
||||
issue_2630_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -740,7 +653,7 @@ issue_2630_3: {
|
||||
issue_3364: {
|
||||
options = {
|
||||
functions: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -805,7 +718,7 @@ issue_3364: {
|
||||
|
||||
defun_label: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -837,7 +750,7 @@ defun_label: {
|
||||
|
||||
iife_func_side_effects: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -889,7 +802,7 @@ iife_func_side_effects: {
|
||||
issue_1595_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -909,7 +822,7 @@ issue_1595_1: {
|
||||
issue_1595_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -929,7 +842,7 @@ issue_1595_2: {
|
||||
issue_1595_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -950,7 +863,7 @@ issue_1595_3: {
|
||||
issue_1595_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -972,7 +885,7 @@ issue_1595_4: {
|
||||
|
||||
duplicate_lambda_defun_name_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
@@ -992,7 +905,7 @@ duplicate_lambda_defun_name_1: {
|
||||
|
||||
duplicate_lambda_defun_name_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -1013,7 +926,7 @@ duplicate_lambda_defun_name_2: {
|
||||
|
||||
function_name_mangle: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
keep_fnames: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -1031,7 +944,7 @@ function_name_mangle: {
|
||||
|
||||
function_name_mangle_ie8: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
keep_fnames: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
@@ -1052,7 +965,7 @@ function_name_mangle_ie8: {
|
||||
|
||||
issue_3420_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1075,7 +988,7 @@ issue_3420_1: {
|
||||
issue_3420_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1096,7 +1009,7 @@ issue_3420_2: {
|
||||
issue_3420_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -1118,7 +1031,7 @@ issue_3420_3: {
|
||||
|
||||
issue_3423_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1138,7 +1051,7 @@ issue_3423_1: {
|
||||
|
||||
issue_3423_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1165,7 +1078,7 @@ collapse_vars_repeated: {
|
||||
hoist_funs: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
loops: true,
|
||||
properties: true,
|
||||
reduce_funcs: true,
|
||||
@@ -1212,7 +1125,7 @@ collapse_vars_repeated: {
|
||||
chained_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1236,7 +1149,7 @@ replace_all_var_scope: {
|
||||
rename = true
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
@@ -1265,7 +1178,7 @@ replace_all_var_scope: {
|
||||
|
||||
issue_1583: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -1302,7 +1215,7 @@ issues_3267_1: {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
@@ -1331,7 +1244,7 @@ issues_3267_1: {
|
||||
|
||||
trailing_argument_side_effects: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1355,7 +1268,7 @@ trailing_argument_side_effects: {
|
||||
|
||||
recursive_iife_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -1374,7 +1287,7 @@ recursive_iife_1: {
|
||||
|
||||
recursive_iife_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -1455,7 +1368,7 @@ issue_3619: {
|
||||
|
||||
issue_4353_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -1470,7 +1383,7 @@ issue_4353_1: {
|
||||
|
||||
issue_4353_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
|
||||
@@ -207,3 +207,123 @@ labels_10: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_4466_1: {
|
||||
mangle = {
|
||||
v8: false,
|
||||
}
|
||||
input: {
|
||||
A: if (console.log("PASS"))
|
||||
B:;
|
||||
else
|
||||
C:;
|
||||
}
|
||||
expect: {
|
||||
e: if (console.log("PASS"))
|
||||
l:;
|
||||
else
|
||||
l:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_4466_1_v8: {
|
||||
mangle = {
|
||||
v8: true,
|
||||
}
|
||||
input: {
|
||||
A: if (console.log("PASS"))
|
||||
B:;
|
||||
else
|
||||
C:;
|
||||
}
|
||||
expect: {
|
||||
e: if (console.log("PASS"))
|
||||
l:;
|
||||
else
|
||||
o:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=12"
|
||||
}
|
||||
|
||||
issue_4466_2: {
|
||||
mangle = {
|
||||
toplevel: false,
|
||||
v8: false,
|
||||
}
|
||||
input: {
|
||||
if (console.log("PASS"))
|
||||
A:;
|
||||
else
|
||||
B:;
|
||||
}
|
||||
expect: {
|
||||
if (console.log("PASS"))
|
||||
e:;
|
||||
else
|
||||
e:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4466_2_v8: {
|
||||
mangle = {
|
||||
toplevel: false,
|
||||
v8: true,
|
||||
}
|
||||
input: {
|
||||
if (console.log("PASS"))
|
||||
A:;
|
||||
else
|
||||
B:;
|
||||
}
|
||||
expect: {
|
||||
if (console.log("PASS"))
|
||||
e:;
|
||||
else
|
||||
l:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4466_2_toplevel: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
v8: false,
|
||||
}
|
||||
input: {
|
||||
if (console.log("PASS"))
|
||||
A:;
|
||||
else
|
||||
B:;
|
||||
}
|
||||
expect: {
|
||||
if (console.log("PASS"))
|
||||
e:;
|
||||
else
|
||||
e:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4466_2_toplevel_v8: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
v8: true,
|
||||
}
|
||||
input: {
|
||||
if (console.log("PASS"))
|
||||
A:;
|
||||
else
|
||||
B:;
|
||||
}
|
||||
expect: {
|
||||
if (console.log("PASS"))
|
||||
e:;
|
||||
else
|
||||
e:;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -359,6 +359,28 @@ reduce_block_2_toplevel: {
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
reduce_vars: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = "PASS";
|
||||
console.log(a);
|
||||
a = "FAIL";
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log("PASS");
|
||||
"FAIL";
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
hoist_props: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
@@ -1228,3 +1250,92 @@ issue_1753_toplevel: {
|
||||
expect_stdout: "0"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4438: {
|
||||
options = {
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f() {
|
||||
if (console) {
|
||||
{
|
||||
let a = console.log;
|
||||
return void a("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f() {
|
||||
if (!console)
|
||||
;
|
||||
else {
|
||||
let a = console.log;
|
||||
a("PASS");
|
||||
}
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4531_1: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a;
|
||||
console.log(function a() {
|
||||
let a;
|
||||
var b;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o;
|
||||
console.log(function o() {
|
||||
let o;
|
||||
var t;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4531_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = console;
|
||||
console.log(typeof a, function a() {
|
||||
let { [console]: a } = 0 && a;
|
||||
var b = console;
|
||||
while (!b);
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o = console;
|
||||
console.log(typeof o, function o() {
|
||||
let { [console]: o } = 0;
|
||||
var e = console;
|
||||
while (!e);
|
||||
}());
|
||||
}
|
||||
expect_stdout: "object undefined"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -1026,7 +1026,7 @@ issue_4075: {
|
||||
|
||||
issue_4082: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
@@ -1050,7 +1050,7 @@ issue_4082: {
|
||||
|
||||
issue_4084: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
@@ -1280,3 +1280,33 @@ issue_4355: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4564: {
|
||||
options = {
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw null;
|
||||
} catch (a) {
|
||||
var a;
|
||||
(function() {
|
||||
for (a in "foo");
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw null;
|
||||
} catch (a) {
|
||||
var a;
|
||||
(function() {
|
||||
for (a in "foo");
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ issue_4103: {
|
||||
|
||||
issue_4107: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
|
||||
@@ -338,7 +338,7 @@ evaluate_3: {
|
||||
console.log(1 + Number(x) + 2);
|
||||
}
|
||||
expect: {
|
||||
console.log(+x + 3);
|
||||
console.log(+("" + x) + 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1386,3 +1386,75 @@ issue_4142: {
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4542_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / (a[0] = 2));
|
||||
}([ 3 ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / (a[0] = 2));
|
||||
}([ 3 ]));
|
||||
}
|
||||
expect_stdout: "4"
|
||||
}
|
||||
|
||||
issue_4542_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / --a[0]);
|
||||
}([ 3 ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / --a[0]);
|
||||
}([ 3 ]));
|
||||
}
|
||||
expect_stdout: "4"
|
||||
}
|
||||
|
||||
issue_4542_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a / (0 / (a[0] = 0, 1));
|
||||
}([ 1 ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a / (0 / (a[0] = 0, 1));
|
||||
}([ 1 ]));
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4542_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / (a.length = 1));
|
||||
}([ 2, 3 ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a / (1 / (a.length = 1));
|
||||
}([ 2, 3 ]));
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ issue_3858: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -711,7 +711,7 @@ inline_pure_call_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
@@ -733,7 +733,7 @@ inline_pure_call_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
@@ -756,7 +756,7 @@ inline_pure_call_3: {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
|
||||
@@ -248,6 +248,35 @@ issue_2110_2: {
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_2110_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function g() {
|
||||
return this;
|
||||
}
|
||||
console.log(typeof function() {
|
||||
function f() {}
|
||||
f.g = g;
|
||||
return f.g();
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
function g() {
|
||||
return this;
|
||||
}
|
||||
console.log(typeof function() {
|
||||
function f() {}
|
||||
f.g = g;
|
||||
return f.g();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
set_immutable_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -979,6 +1008,7 @@ collapse_vars_2_strict: {
|
||||
collapse_rhs_true: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1015,6 +1045,7 @@ collapse_rhs_true: {
|
||||
collapse_rhs_false: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: false,
|
||||
}
|
||||
input: {
|
||||
@@ -1051,6 +1082,7 @@ collapse_rhs_false: {
|
||||
collapse_rhs_strict: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
}
|
||||
input: {
|
||||
@@ -1087,6 +1119,7 @@ collapse_rhs_strict: {
|
||||
collapse_rhs_setter: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
}
|
||||
input: {
|
||||
@@ -1208,3 +1241,32 @@ issue_3427: {
|
||||
expect: {}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4440: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function() {
|
||||
arguments = null;
|
||||
console.log(arguments.p = "FAIL");
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function() {
|
||||
arguments = null;
|
||||
console.log(arguments.p = "FAIL");
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -2373,7 +2373,7 @@ redefine_farg_1: {
|
||||
function f(a) {
|
||||
return typeof a;
|
||||
}
|
||||
function g() {
|
||||
function g(a) {
|
||||
return "number";
|
||||
}
|
||||
function h(a, b) {
|
||||
@@ -6928,7 +6928,7 @@ issue_3622: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
@@ -7196,7 +7196,7 @@ issue_3894: {
|
||||
issue_3922: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
@@ -7601,3 +7601,32 @@ issue_4188_2: {
|
||||
}
|
||||
expect_stdout: "number undefined"
|
||||
}
|
||||
|
||||
issue_4568: {
|
||||
options = {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
a && console.log("FAIL");
|
||||
if (1)
|
||||
do {
|
||||
if (!console.log("PASS")) break;
|
||||
} while (1);
|
||||
})(!(0 !== delete NaN));
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
for (a && console.log("FAIL"), 1; console.log("PASS"); ) 1;
|
||||
})(!(0 !== delete NaN));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
698
test/compress/rests.js
Normal file
698
test/compress/rests.js
Normal file
@@ -0,0 +1,698 @@
|
||||
arrow_1: {
|
||||
input: {
|
||||
console.log.apply(console, ((...a) => a)("PASS", 42));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,((...a)=>a)("PASS",42));'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
arrow_2: {
|
||||
input: {
|
||||
console.log.apply(console, ((a, ...b) => b)("FAIL", "PASS", 42));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,((a,...b)=>b)("FAIL","PASS",42));'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
arrow_destructured_array_1: {
|
||||
input: {
|
||||
console.log.apply(console, (([ ...a ]) => a)("PASS"));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,(([...a])=>a)("PASS"));'
|
||||
expect_stdout: "P A S S"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
arrow_destructured_array_2: {
|
||||
input: {
|
||||
console.log.apply(console, (([ a, ...b ]) => b)([ "FAIL", "PASS", 42 ]));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,(([a,...b])=>b)(["FAIL","PASS",42]));'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
arrow_destructured_array_3: {
|
||||
input: {
|
||||
console.log((([ [ ...a ] = "FAIL" ]) => a)([ "PASS" ]).join("|"));
|
||||
}
|
||||
expect_exact: 'console.log((([[...a]="FAIL"])=>a)(["PASS"]).join("|"));'
|
||||
expect_stdout: "P|A|S|S"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
arrow_destructured_object_1: {
|
||||
input: {
|
||||
var f = ({ ...a }) => a, o = f({ PASS: 42 });
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_exact: "var f=({...a})=>a,o=f({PASS:42});for(var k in o)console.log(k,o[k]);"
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
arrow_destructured_object_2: {
|
||||
input: {
|
||||
var f = ({ FAIL: a, ...b }) => b, o = f({ PASS: 42, FAIL: null });
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_exact: "var f=({FAIL:a,...b})=>b,o=f({PASS:42,FAIL:null});for(var k in o)console.log(k,o[k]);"
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
arrow_destructured_object_3: {
|
||||
input: {
|
||||
var f = ([ { ...a } = [ "FAIL" ] ]) => a;
|
||||
var o = f([ "PASS" ]);
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_exact: 'var f=([{...a}=["FAIL"]])=>a;var o=f(["PASS"]);for(var k in o)console.log(k,o[k]);'
|
||||
expect_stdout: [
|
||||
"0 P",
|
||||
"1 A",
|
||||
"2 S",
|
||||
"3 S",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
funarg_1: {
|
||||
input: {
|
||||
console.log.apply(console, function(...a) {
|
||||
return a;
|
||||
}("PASS", 42));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,function(...a){return a}("PASS",42));'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
funarg_2: {
|
||||
input: {
|
||||
console.log.apply(console, function(a, ...b) {
|
||||
return b;
|
||||
}("FAIL", "PASS", 42));
|
||||
}
|
||||
expect_exact: 'console.log.apply(console,function(a,...b){return b}("FAIL","PASS",42));'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
destructured_array_1: {
|
||||
input: {
|
||||
var [ ...a ] = [ "PASS", 42 ];
|
||||
console.log.apply(console, a);
|
||||
}
|
||||
expect_exact: 'var[...a]=["PASS",42];console.log.apply(console,a);'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
destructured_array_2: {
|
||||
input: {
|
||||
var [ a, ...b ] = [ "FAIL", "PASS", 42 ];
|
||||
console.log.apply(console, b);
|
||||
}
|
||||
expect_exact: 'var[a,...b]=["FAIL","PASS",42];console.log.apply(console,b);'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
destructured_object_1: {
|
||||
input: {
|
||||
var { ...a } = [ "FAIL", "PASS", 42 ];
|
||||
console.log(a[1], a[2]);
|
||||
}
|
||||
expect_exact: 'var{...a}=["FAIL","PASS",42];console.log(a[1],a[2]);'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
destructured_object_2: {
|
||||
input: {
|
||||
var { 0: a, ...b } = [ "FAIL", "PASS", 42 ];
|
||||
console.log(b[1], b[2]);
|
||||
}
|
||||
expect_exact: 'var{0:a,...b}=["FAIL","PASS",42];console.log(b[1],b[2]);'
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
drop_fargs: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
rests: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, ...b) {
|
||||
return b[0];
|
||||
}("FAIL", "PASS"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b) {
|
||||
return b[0];
|
||||
}([ "PASS" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, ...[ b, c ]) {
|
||||
return c + b + a;
|
||||
}("SS", "A", "P"));
|
||||
}
|
||||
expect: {
|
||||
console.log(([ a, ...[ b, c ] ] = [ "SS", "A", "P" ], c + b + a));
|
||||
var a, b, c;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
retain_var: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var [ ...a ] = [ "PASS" ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect: {
|
||||
var [ ...a ] = [ "PASS" ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_destructured_array: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
rests: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var [ ...a ] = [ "PASS" ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log([ "PASS" ][0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_destructured_object: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var { ...a } = [ "PASS" ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect: {
|
||||
var { ...a } = [ "PASS" ];
|
||||
console.log(a[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
retain_destructured_array: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var [ a, ...b ] = [ "FAIL", "PASS", 42 ];
|
||||
console.log.apply(console, b);
|
||||
}
|
||||
expect: {
|
||||
var [ , ...b ] = [ "FAIL", "PASS", 42 ];
|
||||
console.log.apply(console, b);
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
retain_destructured_object_1: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var { 0: a, ...b } = [ "FAIL", "PASS", 42 ];
|
||||
for (var k in b)
|
||||
console.log(k, b[k]);
|
||||
}
|
||||
expect: {
|
||||
var { 0: a, ...b } = [ "FAIL", "PASS", 42 ];
|
||||
for (var k in b)
|
||||
console.log(k, b[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1 PASS",
|
||||
"2 42",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
retain_destructured_object_2: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var { foo: [ a ], ...b } = { foo: [ "FAIL" ], bar: "PASS", baz: 42 };
|
||||
for (var k in b)
|
||||
console.log(k, b[k]);
|
||||
}
|
||||
expect: {
|
||||
var { foo: [], ...b } = { foo: [ "FAIL" ], bar: "PASS", baz: 42 };
|
||||
for (var k in b)
|
||||
console.log(k, b[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"bar PASS",
|
||||
"baz 42",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
retain_funarg_destructured_array_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log((([ ...a ]) => a)([ "PASS" ])[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log((([ ...a ]) => a)([ "PASS" ])[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
retain_funarg_destructured_array_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function([ a, ...b ]) {
|
||||
return b;
|
||||
}("bar")[1]);
|
||||
}
|
||||
expect: {
|
||||
console.log(function([ , ...b ]) {
|
||||
return b;
|
||||
}("bar")[1]);
|
||||
}
|
||||
expect_stdout: "r"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
retain_funarg_destructured_object_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log((({ ...a }) => a)([ "PASS" ])[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log((({ ...a }) => a)([ "PASS" ])[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
retain_funarg_destructured_object_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function({ p: a, ... b }) {
|
||||
return b;
|
||||
}({ p: "FAIL" }).p || "PASS");
|
||||
}
|
||||
expect: {
|
||||
console.log(function({ p: a, ... b }) {
|
||||
return b;
|
||||
}({ p: "FAIL" }).p || "PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
drop_unused_call_args_1: {
|
||||
options = {
|
||||
rests: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(...a) {
|
||||
console.log(a[0]);
|
||||
})(42, console.log("PASS"));
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
console.log(a[0]);
|
||||
})([ 42, console.log("PASS") ]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_unused_call_args_2: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
rests: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, ...b) {
|
||||
return b;
|
||||
}(console).length);
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b) {
|
||||
return b;
|
||||
}((console, [])).length);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
merge_funarg: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function(...a) {
|
||||
var b = a.length;
|
||||
console.log(b);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(...b) {
|
||||
var b = b.length;
|
||||
console.log(b);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "0"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
merge_funarg_destructured_array: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function([ ...a ]) {
|
||||
var b = a.length;
|
||||
console.log(b);
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function([ ...b ]) {
|
||||
var b = b.length;
|
||||
console.log(b);
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
merge_funarg_destructured_object: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function({ ...a }) {
|
||||
var b = a[0];
|
||||
console.log(b);
|
||||
})([ "PASS" ]);
|
||||
}
|
||||
expect: {
|
||||
(function({ ...b }) {
|
||||
var b = b[0];
|
||||
console.log(b);
|
||||
})([ "PASS" ]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_arguments: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
(function(...[ {} ]) {
|
||||
console.log(arguments[0]);
|
||||
})("PASS");
|
||||
}
|
||||
expect: {
|
||||
(function(...[ {} ]) {
|
||||
console.log(arguments[0]);
|
||||
})("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_rest_array: {
|
||||
options = {
|
||||
rests: true,
|
||||
}
|
||||
input: {
|
||||
var [ ...[ a ]] = [ "PASS" ];
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var [ a ] = [ "PASS" ];
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_rest_arrow: {
|
||||
options = {
|
||||
arrows: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
rests: true,
|
||||
}
|
||||
input: {
|
||||
console.log(((...[ a ]) => a)("PASS"));
|
||||
}
|
||||
expect: {
|
||||
console.log((a => a)("PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_rest_lambda: {
|
||||
options = {
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
rests: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f(...[ a ]) {
|
||||
return a;
|
||||
}
|
||||
console.log(f("PASS"), f(42));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
return a;
|
||||
}
|
||||
console.log(f("PASS"), f(42));
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4525_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, ...[]) {
|
||||
a = "FAIL";
|
||||
return arguments[0];
|
||||
}("PASS"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, ...[]) {
|
||||
a = "FAIL";
|
||||
return arguments[0];
|
||||
}("PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4525_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, ...[]) {
|
||||
a = "FAIL";
|
||||
return arguments[0];
|
||||
}("PASS"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, ...[]) {
|
||||
a = "FAIL";
|
||||
return arguments[0];
|
||||
}("PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4538: {
|
||||
options = {
|
||||
rests: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function f(...a) {
|
||||
return a.p, f;
|
||||
}()());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function f(...a) {
|
||||
return a.p, f;
|
||||
}()());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4544_1: {
|
||||
options = {
|
||||
keep_fnames: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function f(...[ {} ]) {})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
[ ...[ {} ] ] = [];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4544_2: {
|
||||
options = {
|
||||
keep_fnames: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function f(a, ...[ {} ]) {})([]);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
[ , ...[ {} ] ] = [ [] ];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4562: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
rests: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log((([ ...[ a ] ]) => a)("foo"));
|
||||
}
|
||||
expect: {
|
||||
console.log((([ a ]) => a)("foo"));
|
||||
}
|
||||
expect_stdout: "f"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4575: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
rests: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
A = "PASS";
|
||||
(function() {
|
||||
var a = 0, b = a;
|
||||
var c = function a(...b) {
|
||||
A;
|
||||
var d = A;
|
||||
console.log(d, b.length);
|
||||
}();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
A = "PASS";
|
||||
(function() {
|
||||
(function(b) {
|
||||
A;
|
||||
var d = A;
|
||||
console.log(d, b.length);
|
||||
})([]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS 0"
|
||||
node_version: ">=6"
|
||||
}
|
||||
@@ -13,6 +13,23 @@ console_log: {
|
||||
]
|
||||
}
|
||||
|
||||
console_log_console: {
|
||||
input: {
|
||||
var log = console.log;
|
||||
log(console);
|
||||
log(typeof console.log);
|
||||
}
|
||||
expect: {
|
||||
var log = console.log;
|
||||
log(console);
|
||||
log(typeof console.log);
|
||||
}
|
||||
expect_stdout: [
|
||||
"{ log: 'function(){}' }",
|
||||
"function",
|
||||
]
|
||||
}
|
||||
|
||||
typeof_arguments: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -81,6 +98,63 @@ log_global: {
|
||||
expect_stdout: "[object global]"
|
||||
}
|
||||
|
||||
log_nested: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = { p: 42 };
|
||||
for (var i = 0; i < 10; i++)
|
||||
o = {
|
||||
p: o,
|
||||
q: function foo() {},
|
||||
};
|
||||
console.log(o);
|
||||
}
|
||||
expect: {
|
||||
var o = { p: 42 };
|
||||
for (var i = 0; i < 10; i++)
|
||||
o = {
|
||||
p: o,
|
||||
q: function() {},
|
||||
};
|
||||
console.log(o);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
timers: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var count = 0, interval = 1000, duration = 3210;
|
||||
var timer = setInterval(function() {
|
||||
console.log(++count);
|
||||
}, interval);
|
||||
setTimeout(function() {
|
||||
clearInterval(timer);
|
||||
}, duration);
|
||||
}
|
||||
expect: {
|
||||
var count = 0;
|
||||
var timer = setInterval(function() {
|
||||
console.log(++count);
|
||||
}, 1000);
|
||||
setTimeout(function() {
|
||||
clearInterval(timer);
|
||||
}, 3210);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
]
|
||||
node_version: ">=0.12"
|
||||
}
|
||||
|
||||
issue_4054: {
|
||||
input: {
|
||||
console.log({
|
||||
|
||||
@@ -436,7 +436,7 @@ trim_new: {
|
||||
|
||||
issue_4325: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
|
||||
@@ -85,6 +85,28 @@ collapse_vars_4: {
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
conditionals_farg: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
function log(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
var a = 42, b = [ "PASS" ], c = [ "FAIL" ];
|
||||
a ? log(...b) : log(...c);
|
||||
}
|
||||
expect: {
|
||||
function log(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
var a = 42, b = [ "PASS" ], c = [ "FAIL" ];
|
||||
log(...a ? b : c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
dont_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
@@ -106,7 +128,7 @@ dont_inline: {
|
||||
do_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
@@ -145,7 +167,7 @@ drop_empty_call_1: {
|
||||
drop_empty_call_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
(function() {})(...[ console.log("PASS") ]);
|
||||
@@ -159,7 +181,7 @@ drop_empty_call_2: {
|
||||
|
||||
convert_hole: {
|
||||
options = {
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
console.log(...[ "PASS", , 42 ]);
|
||||
@@ -192,7 +214,7 @@ keep_property_access: {
|
||||
|
||||
keep_fargs: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -253,7 +275,7 @@ reduce_vars_2: {
|
||||
convert_setter: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -397,7 +419,7 @@ keep_getter_4: {
|
||||
keep_accessor: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -445,7 +467,7 @@ keep_accessor: {
|
||||
object_key_order_1: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -475,7 +497,7 @@ object_key_order_1: {
|
||||
object_key_order_2: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -505,7 +527,7 @@ object_key_order_2: {
|
||||
object_key_order_3: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -535,7 +557,7 @@ object_key_order_3: {
|
||||
object_key_order_4: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -565,7 +587,7 @@ object_key_order_4: {
|
||||
object_spread_array: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -591,7 +613,7 @@ object_spread_array: {
|
||||
object_spread_string: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
@@ -648,7 +670,7 @@ unused_var_side_effects: {
|
||||
issue_4329: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
@@ -727,7 +749,7 @@ issue_4342: {
|
||||
issue_4345: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
@@ -787,7 +809,7 @@ issue_4361: {
|
||||
issue_4363: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
spreads: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
@@ -804,3 +826,124 @@ issue_4363: {
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4556: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var a = "" + [ a++ ];
|
||||
var b = [ ...a ];
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4560_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function(...{
|
||||
[a++]: {},
|
||||
}) {})(2);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
(function(...{
|
||||
[a++]: {},
|
||||
}) {})(2);
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4560_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
(function(...{
|
||||
[a++]: {},
|
||||
}) {})(2);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
(function(...{
|
||||
[a++]: {},
|
||||
}) {})(2);
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4560_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b;
|
||||
[ ...{
|
||||
[a++]: b,
|
||||
} ] = [ "PASS" ];
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b;
|
||||
[ ...{
|
||||
[a++]: b,
|
||||
} ] = [ "PASS" ];
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4614: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function(...[]) {
|
||||
var arguments;
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
(function(...[]) {
|
||||
var arguments;
|
||||
arguments[0];
|
||||
})();
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=6"
|
||||
}
|
||||
285
test/compress/templates.js
Normal file
285
test/compress/templates.js
Normal file
@@ -0,0 +1,285 @@
|
||||
simple: {
|
||||
input: {
|
||||
console.log(`foo
|
||||
bar\nbaz`);
|
||||
}
|
||||
expect_exact: "console.log(`foo\n bar\\nbaz`);"
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
" bar",
|
||||
"baz",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
placeholder: {
|
||||
input: {
|
||||
console.log(`foo ${ function(a, b) {
|
||||
return a * b;
|
||||
}(6, 7) }`);
|
||||
}
|
||||
expect_exact: "console.log(`foo ${function(a,b){return a*b}(6,7)}`);"
|
||||
expect_stdout: "foo 42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
nested: {
|
||||
input: {
|
||||
console.log(`P${`A${"S"}`}S`);
|
||||
}
|
||||
expect_exact: 'console.log(`P${`A${"S"}`}S`);'
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tagged: {
|
||||
input: {
|
||||
console.log(String.raw`foo\nbar`);
|
||||
}
|
||||
expect_exact: "console.log(String.raw`foo\\nbar`);"
|
||||
expect_stdout: "foo\\nbar"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tagged_chain: {
|
||||
input: {
|
||||
function f(strings) {
|
||||
return strings.join("") || f;
|
||||
}
|
||||
console.log(f```${42}``pass`.toUpperCase());
|
||||
}
|
||||
expect_exact: 'function f(strings){return strings.join("")||f}console.log(f```${42}``pass`.toUpperCase());'
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tag_parenthesis_arrow: {
|
||||
input: {
|
||||
console.log((s => s.raw[0])`\tPASS`.slice(2));
|
||||
}
|
||||
expect_exact: "console.log((s=>s.raw[0])`\\tPASS`.slice(2));"
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tag_parenthesis_new: {
|
||||
input: {
|
||||
(new function() {
|
||||
return console.log;
|
||||
})`foo`;
|
||||
}
|
||||
expect_exact: "(new function(){return console.log})`foo`;"
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_escape: {
|
||||
input: {
|
||||
(function(s) {
|
||||
s.forEach((c, i) => console.log(i, c, s.raw[i]));
|
||||
return () => console.log(arguments);
|
||||
})`\uFo${42}`();
|
||||
}
|
||||
expect_exact: "(function(s){s.forEach((c,i)=>console.log(i,c,s.raw[i]));return()=>console.log(arguments)})`\\uFo${42}`();"
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: false,
|
||||
}
|
||||
input: {
|
||||
console.log(`foo ${ function(a, b) {
|
||||
return a * b;
|
||||
}(6, 7) }`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`foo ${42}`);
|
||||
}
|
||||
expect_stdout: "foo 42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
evaluate_templates: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`foo ${ function(a, b) {
|
||||
return a * b;
|
||||
}(6, 7) }`);
|
||||
}
|
||||
expect: {
|
||||
console.log("foo 42");
|
||||
}
|
||||
expect_stdout: "foo 42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
partial_evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`${6 * 7} foo ${console ? `PA` + "SS" : `FA` + `IL`}`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`42 foo ${console ? "PASS" : "FAIL"}`);
|
||||
}
|
||||
expect_stdout: "42 foo PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_evaluate_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`\67 ${6 * 7}`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`\67 42`);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_evaluate_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`\u0${0}b${5}`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`\u0${0}b5`);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_evaluate_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`\u${0}b${5}`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`\u0b5`);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_evaluate_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(String.raw`\u0${0}b${5}`);
|
||||
}
|
||||
expect: {
|
||||
console.log("\\u00b5");
|
||||
}
|
||||
expect_stdout: "\\u00b5"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
unsafe_evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(String.raw`\uFo`);
|
||||
}
|
||||
expect: {
|
||||
console.log("\\uFo");
|
||||
}
|
||||
expect_stdout: "\\uFo"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
side_effects: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
`42`;
|
||||
`${console.log("foo")}`;
|
||||
console.log`\nbar`;
|
||||
}
|
||||
expect: {
|
||||
console.log("foo");
|
||||
console.log`\nbar`;
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
unsafe_side_effects: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
`42`;
|
||||
`${console.log("foo")}`;
|
||||
String.raw`\nbar`;
|
||||
}
|
||||
expect: {
|
||||
console.log("foo");
|
||||
}
|
||||
expect_stdout: "foo"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4604: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, log = console.log;
|
||||
a = "FAIL";
|
||||
(function() {
|
||||
a = "PASS";
|
||||
})``;
|
||||
log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, log = console.log;
|
||||
a = "FAIL";
|
||||
(function() {
|
||||
a = "PASS";
|
||||
})``;
|
||||
log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4606: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
templates: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`${typeof A} ${"\r"} ${"\\"} ${"`"}`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`${typeof A} \r \\ \``);
|
||||
}
|
||||
expect_stdout: "undefined \r \\ `"
|
||||
node_version: ">=4"
|
||||
}
|
||||
3
test/input/reduce/destructured_assign.js
Normal file
3
test/input/reduce/destructured_assign.js
Normal file
@@ -0,0 +1,3 @@
|
||||
var o = {};
|
||||
[ o[1 + .1 + .1] ] = [ 42 ];
|
||||
console.log(o[1.2]);
|
||||
17
test/input/reduce/destructured_assign.reduced.js
Normal file
17
test/input/reduce/destructured_assign.reduced.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// (beautified)
|
||||
var o = {};
|
||||
|
||||
[ o[1 + .1 + .1] ] = [];
|
||||
|
||||
console.log(o);
|
||||
// output: { '1.2000000000000002': undefined }
|
||||
//
|
||||
// minify: { '1.2': undefined }
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "unsafe_math": true
|
||||
// },
|
||||
// "mangle": false,
|
||||
// "validate": true
|
||||
// }
|
||||
@@ -1,14 +1,12 @@
|
||||
// (beautified)
|
||||
try {
|
||||
1 in 0;
|
||||
} catch ({
|
||||
message: message
|
||||
}) {
|
||||
} catch (message) {
|
||||
console.log(message);
|
||||
}
|
||||
// output: Cannot use 'in' operator to search for '1' in 0
|
||||
// output: TypeError: Cannot use 'in' operator to search for '1' in 0
|
||||
//
|
||||
// minify: Cannot use 'in' operator to search for '0' in 0
|
||||
// minify: TypeError: Cannot use 'in' operator to search for '0' in 0
|
||||
//
|
||||
// options: {
|
||||
// "mangle": false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function f(a) {
|
||||
do {
|
||||
console.log(f.length);
|
||||
} while (console.log(f += 0));
|
||||
})();
|
||||
console.log(function(undefined) {
|
||||
return undefined[function() {
|
||||
{}
|
||||
}] || 1 + .1 + .1;
|
||||
}(42));
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
// (beautified)
|
||||
(function f(a) {
|
||||
do {
|
||||
console.log(f.length);
|
||||
} while (console.log(f += 0));
|
||||
})();
|
||||
// output: 1
|
||||
// function(){}0
|
||||
console.log(function() {
|
||||
return 1 + .1 + .1;
|
||||
}());
|
||||
// output: 1.2000000000000002
|
||||
//
|
||||
// minify: 0
|
||||
// function(){}0
|
||||
// minify: 1.2
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "keep_fargs": false,
|
||||
// "unsafe": true
|
||||
// "unsafe_math": true
|
||||
// },
|
||||
// "mangle": false
|
||||
// }
|
||||
@@ -1,8 +1,5 @@
|
||||
console.log(function f(a) {
|
||||
({
|
||||
set p(v) {
|
||||
f++;
|
||||
}
|
||||
});
|
||||
return f.length;
|
||||
}());
|
||||
({
|
||||
set p(v) {
|
||||
console.log(+v + .1 + .1);
|
||||
}
|
||||
}).p = 1;
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
// (beautified)
|
||||
console.log(function f(a) {
|
||||
({
|
||||
set p(v) {
|
||||
f++;
|
||||
}
|
||||
});
|
||||
return f.length;
|
||||
}());
|
||||
// output: 1
|
||||
({
|
||||
set p(v) {
|
||||
console.log(1 + .1 + .1);
|
||||
}
|
||||
}).p = 0;
|
||||
// output: 1.2000000000000002
|
||||
//
|
||||
// minify: 0
|
||||
// minify: 1.2
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "keep_fargs": false,
|
||||
// "unsafe": true
|
||||
// "unsafe_math": true
|
||||
// },
|
||||
// "mangle": false
|
||||
// }
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
var site = "https://browserbench.org/JetStream1.1";
|
||||
if (typeof phantom == "undefined") {
|
||||
require("../tools/exit");
|
||||
require("../tools/tty");
|
||||
var args = process.argv.slice(2);
|
||||
var debug = args.indexOf("--debug");
|
||||
if (debug < 0) {
|
||||
|
||||
40
test/mocha/bug-report.js
Normal file
40
test/mocha/bug-report.js
Normal file
@@ -0,0 +1,40 @@
|
||||
var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
|
||||
describe("UGLIFY_BUG_REPORT", function() {
|
||||
var env = Object.create(process.env);
|
||||
env.UGLIFY_BUG_REPORT = 1;
|
||||
it("Should generate bug report via API", function(done) {
|
||||
exec('"' + process.argv[0] + '"', { env: env }, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, [
|
||||
"// UGLIFY_BUG_REPORT",
|
||||
"// <<undefined>>",
|
||||
"",
|
||||
"//-------------------------------------------------------------",
|
||||
"// INPUT CODE",
|
||||
"...---...",
|
||||
"",
|
||||
].join("\n"));
|
||||
done();
|
||||
}).stdin.end('console.log(require("./").minify("...---...").code);');
|
||||
});
|
||||
it("Should generate bug report via CLI", function(done) {
|
||||
exec('"' + process.argv[0] + '" bin/uglifyjs -mc', { env: env }, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, [
|
||||
"// UGLIFY_BUG_REPORT",
|
||||
"// {",
|
||||
'// "mangle": {},',
|
||||
'// "compress": {}',
|
||||
"// }",
|
||||
"",
|
||||
"//-------------------------------------------------------------",
|
||||
"// STDIN",
|
||||
"...---...",
|
||||
"",
|
||||
].join("\n"));
|
||||
done();
|
||||
}).stdin.end("...---...");
|
||||
});
|
||||
});
|
||||
@@ -56,7 +56,7 @@ describe("bin/uglifyjs", function() {
|
||||
"--source-map", [
|
||||
"names=true",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(),
|
||||
].join(" "), function(err, stdout) {
|
||||
if (err) throw err;
|
||||
var expected = [
|
||||
@@ -84,7 +84,7 @@ describe("bin/uglifyjs", function() {
|
||||
"--source-map", [
|
||||
"names=false",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(),
|
||||
].join(" "), function(err, stdout) {
|
||||
if (err) throw err;
|
||||
var expected = [
|
||||
@@ -171,7 +171,7 @@ describe("bin/uglifyjs", function() {
|
||||
"content=" + mapFile,
|
||||
"includeSources",
|
||||
"url=inline",
|
||||
].join(","),
|
||||
].join(),
|
||||
].join(" ");
|
||||
|
||||
var child = exec(command, function(err, stdout) {
|
||||
|
||||
@@ -3,7 +3,7 @@ var UglifyJS = require("../node");
|
||||
|
||||
describe("Getters and setters", function() {
|
||||
it("Should not accept operator symbols as getter/setter name", function() {
|
||||
var illegalOperators = [
|
||||
[
|
||||
"++",
|
||||
"--",
|
||||
"+",
|
||||
@@ -42,43 +42,26 @@ describe("Getters and setters", function() {
|
||||
"&=",
|
||||
"&&",
|
||||
"||"
|
||||
];
|
||||
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"
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
var testCase = function(data) {
|
||||
return function() {
|
||||
UglifyJS.parse(data.code);
|
||||
};
|
||||
};
|
||||
var fail = function(data) {
|
||||
return function(e) {
|
||||
].reduce(function(tests, illegalOperator) {
|
||||
tests.push({
|
||||
code: "var obj = { get " + illegalOperator + "() { return test; }};",
|
||||
operator: illegalOperator,
|
||||
});
|
||||
tests.push({
|
||||
code: "var obj = { set " + illegalOperator + "(value) { test = value; }};",
|
||||
operator: illegalOperator,
|
||||
});
|
||||
return tests;
|
||||
}, []).forEach(function(test) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(test.code);
|
||||
}, test.operator == "=" ? function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: operator «" + 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));
|
||||
}
|
||||
&& /^Unexpected token: punc «{», expected: punc «.*?»$/.test(e.message);
|
||||
} : function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: operator «" + test.operator + "»";
|
||||
}, "Expected but didn't get a syntax error while parsing following line:\n" + test.code);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -89,4 +89,13 @@ describe("Number literals", function() {
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
it("Should reject invalid syntax under expression=true", function() {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse("42.g", {
|
||||
expression: true,
|
||||
});
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,8 +37,7 @@ describe("test/reduce.js", function() {
|
||||
it("Should retain setter arguments", function() {
|
||||
var result = reduce_test(read("test/input/reduce/setter.js"), {
|
||||
compress: {
|
||||
keep_fargs: false,
|
||||
unsafe: true,
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
}, {
|
||||
@@ -110,28 +109,24 @@ describe("test/reduce.js", function() {
|
||||
});
|
||||
it("Should print correct output for irreducible test case", function() {
|
||||
var result = reduce_test([
|
||||
"console.log(function f(a) {",
|
||||
" return f.length;",
|
||||
"}());",
|
||||
"console.log(1 + .1 + .1);",
|
||||
].join("\n"), {
|
||||
compress: {
|
||||
keep_fargs: false,
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, [
|
||||
"// (beautified)",
|
||||
"console.log(function f(a) {",
|
||||
" return f.length;",
|
||||
"}());",
|
||||
"// output: 1",
|
||||
"console.log(1 + .1 + .1);",
|
||||
"// output: 1.2000000000000002",
|
||||
"// ",
|
||||
"// minify: 0",
|
||||
"// minify: 1.2",
|
||||
"// ",
|
||||
"// options: {",
|
||||
'// "compress": {',
|
||||
'// "keep_fargs": false',
|
||||
'// "unsafe_math": true',
|
||||
"// },",
|
||||
'// "mangle": false',
|
||||
"// }",
|
||||
@@ -303,8 +298,7 @@ describe("test/reduce.js", function() {
|
||||
if (semver.satisfies(process.version, "<=0.10")) return;
|
||||
var result = reduce_test(read("test/input/reduce/diff_error.js"), {
|
||||
compress: {
|
||||
keep_fargs: false,
|
||||
unsafe: true,
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
}, {
|
||||
@@ -313,6 +307,18 @@ describe("test/reduce.js", function() {
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
|
||||
});
|
||||
it("Should maintain valid LHS in destructuring assignments", function() {
|
||||
if (semver.satisfies(process.version, "<6")) return;
|
||||
var result = reduce_test(read("test/input/reduce/destructured_assign.js"), {
|
||||
compress: {
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
validate: true,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("test/input/reduce/destructured_assign.reduced.js"));
|
||||
});
|
||||
it("Should handle destructured catch expressions", function() {
|
||||
if (semver.satisfies(process.version, "<6")) return;
|
||||
var result = reduce_test(read("test/input/reduce/destructured_catch.js"), {
|
||||
|
||||
@@ -244,6 +244,39 @@ describe("sourcemaps", function() {
|
||||
assert.strictEqual(result.code, '(function(){console.log("hello")}).call(this);');
|
||||
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI"}');
|
||||
});
|
||||
it("Should not overwrite existing sourcesContent", function() {
|
||||
var result = UglifyJS.minify({
|
||||
"in.js": [
|
||||
'"use strict";',
|
||||
"",
|
||||
"var _window$foo = window.foo,",
|
||||
" a = _window$foo[0],",
|
||||
" b = _window$foo[1];",
|
||||
].join("\n"),
|
||||
}, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: {
|
||||
version: 3,
|
||||
sources: [ "in.js" ],
|
||||
names: [
|
||||
"window",
|
||||
"foo",
|
||||
"a",
|
||||
"b",
|
||||
],
|
||||
mappings: ";;kBAAaA,MAAM,CAACC,G;IAAfC,C;IAAGC,C",
|
||||
file: "in.js",
|
||||
sourcesContent: [ "let [a, b] = window.foo;\n" ],
|
||||
},
|
||||
includeSources: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '"use strict";var _window$foo=window.foo,a=_window$foo[0],b=_window$foo[1];');
|
||||
assert.strictEqual(result.map, '{"version":3,"sources":["in.js"],"sourcesContent":["let [a, b] = window.foo;\\n"],"names":["window","foo","a","b"],"mappings":"6BAAaA,OAAOC,IAAfC,E,eAAGC,E"}');
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceMapInline", function() {
|
||||
|
||||
@@ -115,8 +115,8 @@ describe("String literals", function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Invalid hex-character pattern in string";
|
||||
});
|
||||
&& /^Invalid escape sequence: \\u/.test(e.message);
|
||||
}, test);
|
||||
});
|
||||
});
|
||||
it("Should reject invalid code points in Unicode escape sequence", function() {
|
||||
@@ -130,8 +130,8 @@ describe("String literals", function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& /^Invalid character code: /.test(e.message);
|
||||
});
|
||||
&& /^Invalid escape sequence: \\u{1/.test(e.message);
|
||||
}, test);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
67
test/mocha/templates.js
Normal file
67
test/mocha/templates.js
Normal file
@@ -0,0 +1,67 @@
|
||||
var assert = require("assert");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var semver = require("semver");
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("Template literals", function() {
|
||||
it("Should reject invalid literal", function() {
|
||||
[
|
||||
"`foo\\`",
|
||||
"`foo${bar`",
|
||||
"`foo${bar}",
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(input);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated template literal";
|
||||
}, input);
|
||||
});
|
||||
});
|
||||
it("Should reject invalid expression", function() {
|
||||
[
|
||||
"`foo${bar;}`",
|
||||
"`foo${42bar}`",
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(input);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, input);
|
||||
});
|
||||
});
|
||||
it("Should process line-break characters correctly", function() {
|
||||
[
|
||||
// native line breaks
|
||||
[ "`foo\nbar`", "`foo\nbar`" ],
|
||||
[ "`foo\rbar`", "`foo\rbar`" ],
|
||||
[ "`foo\r\nbar`", "`foo\nbar`" ],
|
||||
[ "`foo\r\n\rbar`", "`foo\n\rbar`" ],
|
||||
// escaped line breaks
|
||||
[ "`foo\\nbar`", "`foo\\nbar`" ],
|
||||
[ "`foo\\rbar`", "`foo\\rbar`" ],
|
||||
[ "`foo\r\\nbar`", "`foo\r\\nbar`" ],
|
||||
[ "`foo\\r\nbar`", "`foo\\r\nbar`" ],
|
||||
[ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ],
|
||||
// continuation
|
||||
[ "`foo\\\nbar`", "`foo\\\nbar`" ],
|
||||
[ "`foo\\\rbar`", "`foo\\\rbar`" ],
|
||||
[ "`foo\\\r\nbar`", "`foo\\\nbar`" ],
|
||||
[ "`foo\\\r\n\rbar`", "`foo\\\n\rbar`" ],
|
||||
[ "`foo\\\\nbar`", "`foo\\\\nbar`" ],
|
||||
[ "`foo\\\\rbar`", "`foo\\\\rbar`" ],
|
||||
[ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ],
|
||||
].forEach(function(test) {
|
||||
var input = "console.log(" + test[0] + ");";
|
||||
var result = UglifyJS.minify(input, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var expected = "console.log(" + test[1] + ");";
|
||||
assert.strictEqual(result.code, expected, test[0]);
|
||||
if (semver.satisfies(process.version, "<4")) return;
|
||||
assert.strictEqual(run_code(result.code), run_code(input), test[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -70,8 +70,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
} else if (differs.error) {
|
||||
differs.warnings = warnings;
|
||||
return differs;
|
||||
} else if (is_error(differs.unminified_result)
|
||||
&& is_error(differs.minified_result)
|
||||
} else if (sandbox.is_error(differs.unminified_result)
|
||||
&& sandbox.is_error(differs.minified_result)
|
||||
&& differs.unminified_result.name == differs.minified_result.name) {
|
||||
return {
|
||||
code: [
|
||||
@@ -104,15 +104,14 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// quick ignores
|
||||
if (node instanceof U.AST_Accessor) return;
|
||||
if (node instanceof U.AST_Destructured) return;
|
||||
if (node instanceof U.AST_Directive) return;
|
||||
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||
if (node instanceof U.AST_Label) return;
|
||||
if (node instanceof U.AST_LabelRef) return;
|
||||
if (!in_list && node instanceof U.AST_SymbolDeclaration) return;
|
||||
if (node instanceof U.AST_Toplevel) return;
|
||||
var parent = tt.parent();
|
||||
if (node instanceof U.AST_SymbolFunarg && parent instanceof U.AST_Accessor) return;
|
||||
if (!in_list && parent.rest !== node && node instanceof U.AST_SymbolDeclaration) return;
|
||||
|
||||
// ensure that the _permute prop is a number.
|
||||
// can not use `node.start._permute |= 0;` as it will erase fractional part.
|
||||
@@ -124,7 +123,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// ignore lvalues
|
||||
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||
if (parent instanceof U.AST_DestructuredArray) return;
|
||||
if (parent instanceof U.AST_DefaultValue && parent.name === node) return;
|
||||
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
|
||||
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||
case "++":
|
||||
@@ -153,6 +152,20 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
node.left,
|
||||
node.right,
|
||||
][ permute & 1 ];
|
||||
if (expr instanceof U.AST_Destructured) expr = expr.transform(new U.TreeTransformer(function(node, descend) {
|
||||
if (node instanceof U.AST_DefaultValue) return new U.AST_Assign({
|
||||
operator: "=",
|
||||
left: node.name.transform(this),
|
||||
right: node.value,
|
||||
start: {},
|
||||
});
|
||||
if (node instanceof U.AST_DestructuredKeyVal) return new U.AST_ObjectKeyVal(node);
|
||||
if (node instanceof U.AST_Destructured) {
|
||||
node = new (node instanceof U.AST_DestructuredArray ? U.AST_Array : U.AST_Object)(node);
|
||||
descend(node, this);
|
||||
}
|
||||
return node;
|
||||
}));
|
||||
CHANGED = true;
|
||||
return permute < 2 ? expr : wrap_with_console_log(expr);
|
||||
}
|
||||
@@ -211,6 +224,28 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
node.alternative,
|
||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||
}
|
||||
else if (node instanceof U.AST_DefaultValue) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return node.name;
|
||||
}
|
||||
else if (node instanceof U.AST_DestructuredArray) {
|
||||
var expr = node.elements[0];
|
||||
if (expr && !(expr instanceof U.AST_Hole)) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_DestructuredObject) {
|
||||
// first property's value
|
||||
var expr = node.properties[0];
|
||||
if (expr) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return expr.value;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_Defun) {
|
||||
switch (((node.start._permute += step) * steps | 0) % 2) {
|
||||
case 0:
|
||||
@@ -304,7 +339,16 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
else if (node instanceof U.AST_Object) {
|
||||
// first property's value
|
||||
var expr = node.properties[0] instanceof U.AST_ObjectKeyVal && node.properties[0].value;
|
||||
var expr = node.properties[0];
|
||||
if (expr instanceof U.AST_ObjectKeyVal) {
|
||||
expr = expr.value;
|
||||
} else if (expr instanceof U.AST_Spread) {
|
||||
expr = expr.expression;
|
||||
} else if (expr && expr.key instanceof U.AST_Node) {
|
||||
expr = expr.key;
|
||||
} else {
|
||||
expr = null;
|
||||
}
|
||||
if (expr) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
@@ -314,7 +358,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
else if (node instanceof U.AST_PropAccess) {
|
||||
var expr = [
|
||||
node.expression,
|
||||
node.property instanceof U.AST_Node && node.property,
|
||||
node.property instanceof U.AST_Node && !(parent instanceof U.AST_Destructured) && node.property,
|
||||
][ node.start._permute++ % 2 ];
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
@@ -416,15 +460,10 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
}
|
||||
|
||||
// skip element/property from (destructured) array/object
|
||||
if (parent instanceof U.AST_Array
|
||||
|| parent instanceof U.AST_Destructured
|
||||
|| parent instanceof U.AST_Object) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
}
|
||||
} else if (parent.rest === node) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// replace this node
|
||||
@@ -519,8 +558,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
log(code);
|
||||
log(diff.error.stack);
|
||||
log("*** Discarding permutation and continuing.");
|
||||
} else if (is_error(diff.unminified_result)
|
||||
&& is_error(diff.minified_result)
|
||||
} else if (sandbox.is_error(diff.unminified_result)
|
||||
&& sandbox.is_error(diff.minified_result)
|
||||
&& diff.unminified_result.name == diff.minified_result.name) {
|
||||
// ignore difference in error messages caused by minification
|
||||
diff_error_message = testcase;
|
||||
@@ -561,10 +600,10 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
var lines = [ "" ];
|
||||
if (isNaN(max_timeout)) {
|
||||
lines.push("// minify error: " + to_comment(strip_color_codes(differs.minified_result.stack)));
|
||||
lines.push("// minify error: " + to_comment(differs.minified_result.stack));
|
||||
} else {
|
||||
var unminified_result = strip_color_codes(differs.unminified_result);
|
||||
var minified_result = strip_color_codes(differs.minified_result);
|
||||
var unminified_result = differs.unminified_result;
|
||||
var minified_result = differs.minified_result;
|
||||
if (trim_trailing_whitespace(unminified_result) == trim_trailing_whitespace(minified_result)) {
|
||||
lines.push(
|
||||
"// (stringified)",
|
||||
@@ -585,10 +624,6 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
};
|
||||
|
||||
function strip_color_codes(value) {
|
||||
return ("" + value).replace(/\u001b\[\d+m/g, "");
|
||||
}
|
||||
|
||||
function to_comment(value) {
|
||||
return ("" + value).replace(/\n/g, "\n// ");
|
||||
}
|
||||
@@ -626,17 +661,16 @@ function has_loopcontrol(body, loop, label) {
|
||||
return found;
|
||||
}
|
||||
|
||||
function is_error(result) {
|
||||
return typeof result == "object" && typeof result.name == "string" && typeof result.message == "string";
|
||||
}
|
||||
|
||||
function is_timed_out(result) {
|
||||
return is_error(result) && /timed out/.test(result.message);
|
||||
return sandbox.is_error(result) && /timed out/.test(result.message);
|
||||
}
|
||||
|
||||
function is_statement(node) {
|
||||
return node instanceof U.AST_Statement
|
||||
&& !(node instanceof U.AST_Arrow || node instanceof U.AST_AsyncFunction || node instanceof U.AST_Function);
|
||||
&& !(node instanceof U.AST_Arrow
|
||||
|| node instanceof U.AST_AsyncArrow
|
||||
|| node instanceof U.AST_AsyncFunction
|
||||
|| node instanceof U.AST_Function);
|
||||
}
|
||||
|
||||
function merge_sequence(array, node) {
|
||||
|
||||
342
test/sandbox.js
342
test/sandbox.js
@@ -1,93 +1,39 @@
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var semver = require("semver");
|
||||
var spawnSync = require("child_process").spawnSync;
|
||||
var vm = require("vm");
|
||||
|
||||
var setupContext = new vm.Script([
|
||||
"[ Array, Boolean, Error, Function, Number, Object, RegExp, String ].forEach(function(f) {",
|
||||
" f.toString = Function.prototype.toString;",
|
||||
"});",
|
||||
"Function.prototype.toString = function() {",
|
||||
" var id = 100000;",
|
||||
" return function() {",
|
||||
" var n = this.name;",
|
||||
" if (!/^F[0-9]{6}N$/.test(n)) {",
|
||||
' n = "F" + ++id + "N";',
|
||||
].concat(Object.getOwnPropertyDescriptor(Function.prototype, "name").configurable ? [
|
||||
' Object.defineProperty(this, "name", {',
|
||||
" get: function() {",
|
||||
" return n;",
|
||||
" }",
|
||||
" });",
|
||||
] : [], [
|
||||
" }",
|
||||
' return "function(){}";',
|
||||
" };",
|
||||
"}();",
|
||||
"this;",
|
||||
]).join("\n"));
|
||||
|
||||
function createContext() {
|
||||
var ctx = vm.createContext(Object.defineProperties({}, {
|
||||
console: { value: { log: log } },
|
||||
global: { get: self },
|
||||
self: { get: self },
|
||||
window: { get: self },
|
||||
}));
|
||||
var global = setupContext.runInContext(ctx);
|
||||
return ctx;
|
||||
|
||||
function self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
function safe_log(arg, level) {
|
||||
if (arg) switch (typeof arg) {
|
||||
case "function":
|
||||
return arg.toString();
|
||||
case "object":
|
||||
if (arg === global) return "[object global]";
|
||||
if (/Error$/.test(arg.name)) return arg.toString();
|
||||
if (typeof arg.then == "function") return "[object Promise]";
|
||||
arg.constructor.toString();
|
||||
if (level--) for (var key in arg) {
|
||||
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
||||
if (!desc || !desc.get && !desc.set) arg[key] = safe_log(arg[key], level);
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
function log(msg) {
|
||||
if (arguments.length == 1 && typeof msg == "string") return console.log("%s", msg);
|
||||
return console.log.apply(console, [].map.call(arguments, function(arg) {
|
||||
return safe_log(arg, 3);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
exports.run_code = function(code, toplevel, timeout) {
|
||||
timeout = timeout || 5000;
|
||||
var stdout = "";
|
||||
var original_write = process.stdout.write;
|
||||
process.stdout.write = function(chunk) {
|
||||
stdout += chunk;
|
||||
};
|
||||
try {
|
||||
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: timeout });
|
||||
return stdout;
|
||||
} catch (ex) {
|
||||
return ex;
|
||||
} finally {
|
||||
process.stdout.write = original_write;
|
||||
setup_log();
|
||||
var setup_code = "(" + setup + ")(" + [
|
||||
"this",
|
||||
find_builtins(),
|
||||
setup_log,
|
||||
"function(process) {" + readFileSync(require.resolve("../tools/tty", "utf8")) + "}",
|
||||
].join(",\n") + ");\n";
|
||||
exports.has_toplevel = function(options) {
|
||||
return options.toplevel
|
||||
|| options.mangle && options.mangle.toplevel
|
||||
|| options.compress && options.compress.toplevel;
|
||||
};
|
||||
exports.is_error = is_error;
|
||||
exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, toplevel, timeout) {
|
||||
var stdout = run_code_vm(code, toplevel, timeout);
|
||||
if (typeof stdout != "string" || !/arguments/.test(code)) return stdout;
|
||||
do {
|
||||
var prev = stdout;
|
||||
stdout = run_code_vm(code, toplevel, timeout);
|
||||
} while (prev !== stdout);
|
||||
return stdout;
|
||||
} : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) {
|
||||
if (/\basync([ \t]+[^\s()[\]{},.&|!~=*%/+-]+|[ \t]*\([\s\S]*?\))[ \t]*=>|\b(async[ \t]+function|setInterval|setTimeout)\b/.test(code)) {
|
||||
return run_code_exec(code, toplevel, timeout);
|
||||
} else {
|
||||
return run_code_vm(code, toplevel, timeout);
|
||||
}
|
||||
};
|
||||
|
||||
function strip_func_ids(text) {
|
||||
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
|
||||
}
|
||||
|
||||
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
|
||||
if (typeof expected != typeof actual) return false;
|
||||
if (typeof expected == "object" && typeof expected.name == "string" && typeof expected.message == "string") {
|
||||
if (is_error(expected)) {
|
||||
if (expected.name !== actual.name) return false;
|
||||
if (typeof actual.message != "string") return false;
|
||||
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
|
||||
@@ -97,8 +43,228 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
|
||||
} : function(expected, actual) {
|
||||
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
||||
};
|
||||
exports.has_toplevel = function(options) {
|
||||
return options.toplevel
|
||||
|| options.mangle && options.mangle.toplevel
|
||||
|| options.compress && options.compress.toplevel;
|
||||
};
|
||||
|
||||
function is_error(result) {
|
||||
return result && typeof result.name == "string" && typeof result.message == "string";
|
||||
}
|
||||
|
||||
function strip_color_codes(value) {
|
||||
return value.replace(/\u001b\[\d+m/g, "");
|
||||
}
|
||||
|
||||
function strip_func_ids(text) {
|
||||
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
|
||||
}
|
||||
|
||||
function setup_log() {
|
||||
var inspect = require("util").inspect;
|
||||
if (inspect.defaultOptions) {
|
||||
var log_options = {
|
||||
breakLength: Infinity,
|
||||
colors: false,
|
||||
compact: true,
|
||||
customInspect: false,
|
||||
depth: Infinity,
|
||||
maxArrayLength: Infinity,
|
||||
maxStringLength: Infinity,
|
||||
showHidden: false,
|
||||
};
|
||||
for (var name in log_options) {
|
||||
if (name in inspect.defaultOptions) inspect.defaultOptions[name] = log_options[name];
|
||||
}
|
||||
}
|
||||
return inspect;
|
||||
}
|
||||
|
||||
function find_builtins() {
|
||||
setup_code = "console.log(Object.keys(this));";
|
||||
var builtins = run_code_vm("");
|
||||
if (semver.satisfies(process.version, ">=0.12")) builtins += ".concat(" + run_code_exec("") + ")";
|
||||
return builtins;
|
||||
}
|
||||
|
||||
function setup(global, builtins, setup_log, setup_tty) {
|
||||
[ Array, Boolean, Error, Function, Number, Object, RegExp, String ].forEach(function(f) {
|
||||
f.toString = Function.prototype.toString;
|
||||
});
|
||||
Function.prototype.toString = function() {
|
||||
var configurable = Object.getOwnPropertyDescriptor(Function.prototype, "name").configurable;
|
||||
var id = 100000;
|
||||
return function() {
|
||||
var n = this.name;
|
||||
if (!/^F[0-9]{6}N$/.test(n)) {
|
||||
n = "F" + ++id + "N";
|
||||
if (configurable) Object.defineProperty(this, "name", {
|
||||
get: function() {
|
||||
return n;
|
||||
}
|
||||
});
|
||||
}
|
||||
return "function(){}";
|
||||
};
|
||||
}();
|
||||
var process = global.process;
|
||||
if (process) {
|
||||
setup_tty(process);
|
||||
var inspect = setup_log();
|
||||
process.on("uncaughtException", function(ex) {
|
||||
var value = ex;
|
||||
if (value instanceof Error) {
|
||||
value = {};
|
||||
for (var name in ex) {
|
||||
value[name] = ex[name];
|
||||
delete ex[name];
|
||||
}
|
||||
}
|
||||
process.stderr.write(inspect(value) + "\n\n-----===== UNCAUGHT EXCEPTION =====-----\n\n");
|
||||
throw ex;
|
||||
}).on("unhandledRejection", function() {});
|
||||
}
|
||||
var log = console.log;
|
||||
var safe_console = {
|
||||
log: function(msg) {
|
||||
if (arguments.length == 1 && typeof msg == "string") return log("%s", msg);
|
||||
return log.apply(null, [].map.call(arguments, function(arg) {
|
||||
return safe_log(arg, {
|
||||
level: 5,
|
||||
original: [],
|
||||
replaced: [],
|
||||
});
|
||||
}));
|
||||
},
|
||||
};
|
||||
var props = {
|
||||
// for Node.js v8
|
||||
console: {
|
||||
get: function() {
|
||||
return safe_console;
|
||||
},
|
||||
},
|
||||
global: { get: self },
|
||||
self: { get: self },
|
||||
window: { get: self },
|
||||
};
|
||||
[
|
||||
// for Node.js v0.12
|
||||
"Buffer",
|
||||
"clearInterval",
|
||||
"clearTimeout",
|
||||
// for Node.js v0.12
|
||||
"DTRACE_NET_STREAM_END",
|
||||
// for Node.js v8
|
||||
"process",
|
||||
"setInterval",
|
||||
"setTimeout",
|
||||
].forEach(function(name) {
|
||||
var value = global[name];
|
||||
props[name] = {
|
||||
get: function() {
|
||||
return value;
|
||||
},
|
||||
};
|
||||
});
|
||||
builtins.forEach(function(name) {
|
||||
try {
|
||||
delete global[name];
|
||||
} catch (e) {}
|
||||
});
|
||||
Object.defineProperties(global, props);
|
||||
// for Node.js v8+
|
||||
global.toString = function() {
|
||||
return "[object global]";
|
||||
};
|
||||
|
||||
function self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
function safe_log(arg, cache) {
|
||||
if (arg) switch (typeof arg) {
|
||||
case "function":
|
||||
return arg.toString();
|
||||
case "object":
|
||||
if (arg === global) return "[object global]";
|
||||
if (/Error$/.test(arg.name)) return arg.toString();
|
||||
if (typeof arg.then == "function") return "[object Promise]";
|
||||
arg.constructor.toString();
|
||||
var index = cache.original.indexOf(arg);
|
||||
if (index >= 0) return cache.replaced[index];
|
||||
if (--cache.level < 0) return "[object Object]";
|
||||
var value = {};
|
||||
cache.original.push(arg);
|
||||
cache.replaced.push(value);
|
||||
for (var key in arg) {
|
||||
var desc = Object.getOwnPropertyDescriptor(arg, key);
|
||||
if (desc && (desc.get || desc.set)) {
|
||||
Object.defineProperty(value, key, desc);
|
||||
} else {
|
||||
value[key] = safe_log(arg[key], cache);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
function run_code_vm(code, toplevel, timeout) {
|
||||
timeout = timeout || 5000;
|
||||
var stdout = "";
|
||||
var original_write = process.stdout.write;
|
||||
process.stdout.write = function(chunk) {
|
||||
stdout += chunk;
|
||||
};
|
||||
try {
|
||||
var ctx = vm.createContext({ console: console });
|
||||
// for Node.js v6
|
||||
vm.runInContext(setup_code, ctx);
|
||||
vm.runInContext(toplevel ? "(function(){" + code + "})();" : code, ctx, { timeout: timeout });
|
||||
return strip_color_codes(stdout);
|
||||
} catch (ex) {
|
||||
return ex;
|
||||
} finally {
|
||||
process.stdout.write = original_write;
|
||||
}
|
||||
}
|
||||
|
||||
function run_code_exec(code, toplevel, timeout) {
|
||||
if (toplevel) {
|
||||
code = setup_code + "(function(){" + code + "})();";
|
||||
} else {
|
||||
code = code.replace(/^((["'])[^"']*\2(;|$))?/, function(directive) {
|
||||
return directive + setup_code;
|
||||
});
|
||||
}
|
||||
var result = spawnSync(process.argv[0], [ '--max-old-space-size=2048' ], {
|
||||
encoding: "utf8",
|
||||
input: code,
|
||||
stdio: "pipe",
|
||||
timeout: timeout || 5000,
|
||||
});
|
||||
if (result.status === 0) return result.stdout;
|
||||
if (result.error && result.error.code == "ETIMEDOUT" || /FATAL ERROR:/.test(msg)) {
|
||||
return new Error("Script execution timed out.");
|
||||
}
|
||||
if (result.error) return result.error;
|
||||
var msg = result.stderr.replace(/\r\n/g, "\n");
|
||||
var end = msg.indexOf("\n\n-----===== UNCAUGHT EXCEPTION =====-----\n\n");
|
||||
var details;
|
||||
if (end >= 0) {
|
||||
details = msg.slice(0, end).replace(/<([1-9][0-9]*) empty items?>/g, function(match, count) {
|
||||
return new Array(+count).join();
|
||||
});
|
||||
try {
|
||||
details = vm.runInNewContext("(" + details + ")");
|
||||
} catch (e) {}
|
||||
}
|
||||
var match = /\n([^:\s]*Error)(?:: ([\s\S]+?))?\n( at [\s\S]+)\n$/.exec(msg);
|
||||
if (!match) return details;
|
||||
var ex = new global[match[1]](match[2]);
|
||||
ex.stack = ex.stack.slice(0, ex.stack.indexOf(" at ")) + match[3];
|
||||
if (typeof details == "object") {
|
||||
for (var name in details) ex[name] = details[name];
|
||||
} else if (end >= 0) {
|
||||
ex.details = details;
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
@@ -10,16 +10,17 @@ exports.init = function(url, auth, num) {
|
||||
exports.should_stop = function(callback) {
|
||||
read(base + "/actions/runs?per_page=100", function(reply) {
|
||||
if (!reply || !Array.isArray(reply.workflow_runs)) return;
|
||||
var runs = reply.workflow_runs.filter(function(workflow) {
|
||||
return workflow.status != "completed";
|
||||
}).sort(function(a, b) {
|
||||
var runs = reply.workflow_runs.sort(function(a, b) {
|
||||
return b.run_number - a.run_number;
|
||||
});
|
||||
var found = false, remaining = 20;
|
||||
(function next() {
|
||||
if (!runs.length) return;
|
||||
var workflow = runs.pop();
|
||||
if (workflow.event == "schedule" && workflow.run_number == run_number) found = true;
|
||||
var workflow;
|
||||
do {
|
||||
workflow = runs.pop();
|
||||
if (!workflow) return;
|
||||
if (workflow.event == "schedule" && workflow.run_number == run_number) found = true;
|
||||
} while (!found && workflow.status == "completed");
|
||||
read(workflow.jobs_url, function(reply) {
|
||||
if (!reply || !Array.isArray(reply.jobs)) return;
|
||||
if (!reply.jobs.every(function(job) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m
|
||||
// cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node
|
||||
|
||||
require("../../tools/exit");
|
||||
require("../../tools/tty");
|
||||
|
||||
var UglifyJS = require("../..");
|
||||
var randomBytes = require("crypto").randomBytes;
|
||||
@@ -134,13 +134,19 @@ var SUPPORT = function(matrix) {
|
||||
}({
|
||||
arrow: "a => 0;",
|
||||
async: "async function f(){}",
|
||||
bigint: "42n",
|
||||
catch_omit_var: "try {} catch {}",
|
||||
computed_key: "({[0]: 0});",
|
||||
const_block: "var a; { const a = 0; }",
|
||||
default_value: "[ a = 0 ] = [];",
|
||||
destructuring: "[] = [];",
|
||||
exponentiation: "0 ** 0",
|
||||
let: "let a;",
|
||||
rest: "var [...a] = [];",
|
||||
rest_object: "var {...a} = {};",
|
||||
spread: "[...[]];",
|
||||
spread_object: "({...0});",
|
||||
template: "``",
|
||||
trailing_comma: "function f(a,) {}",
|
||||
});
|
||||
|
||||
@@ -164,7 +170,7 @@ var VALUES = [
|
||||
"4",
|
||||
"5",
|
||||
"22",
|
||||
"-0", // 0/-0 !== 0
|
||||
"(-0)", // 0/-0 !== 0
|
||||
"23..toString()",
|
||||
"24 .toString()",
|
||||
"25. ",
|
||||
@@ -185,6 +191,12 @@ var VALUES = [
|
||||
'"function"',
|
||||
"this",
|
||||
];
|
||||
if (SUPPORT.bigint) VALUES = VALUES.concat([
|
||||
"(!0o644n)",
|
||||
"([3n][0] > 2)",
|
||||
"(-42n).toString()",
|
||||
"Number(0XDEADn << 16n | 0xbeefn)",
|
||||
]);
|
||||
|
||||
var BINARY_OPS = [
|
||||
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
||||
@@ -214,6 +226,7 @@ var BINARY_OPS = [
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
if (SUPPORT.exponentiation) BINARY_OPS.push("**");
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
|
||||
BINARY_OPS.push(" in ");
|
||||
@@ -314,8 +327,6 @@ var VAR_NAMES = [
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"arguments",
|
||||
"Math",
|
||||
"parseInt",
|
||||
"async",
|
||||
"await",
|
||||
];
|
||||
@@ -399,8 +410,9 @@ function createParams(was_async, noDuplicate) {
|
||||
return addTrailingComma(params.join(", "));
|
||||
}
|
||||
|
||||
function createArgs(recurmax, stmtDepth, canThrow) {
|
||||
function createArgs(recurmax, stmtDepth, canThrow, noTemplate) {
|
||||
recurmax--;
|
||||
if (SUPPORT.template && !noTemplate && rng(20) == 0) return createTemplateLiteral(recurmax, stmtDepth, canThrow);
|
||||
var args = [];
|
||||
for (var n = rng(4); --n >= 0;) switch (SUPPORT.spread ? rng(50) : 3) {
|
||||
case 0:
|
||||
@@ -419,24 +431,70 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
||||
args.push(rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow));
|
||||
break;
|
||||
}
|
||||
return addTrailingComma(args.join(", "));
|
||||
return "(" + addTrailingComma(args.join(", ")) + ")";
|
||||
}
|
||||
|
||||
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
|
||||
var avoid = [];
|
||||
var len = unique_vars.length;
|
||||
var pairs = createPairs(recurmax);
|
||||
var pairs = createPairs(recurmax, !nameLenBefore);
|
||||
pairs.has_rest = nameLenBefore && convertToRest(pairs.names);
|
||||
unique_vars.length = len;
|
||||
return pairs;
|
||||
|
||||
function createAssignmentValue(recurmax) {
|
||||
function mapShuffled(values, fn) {
|
||||
var declare_only = [];
|
||||
var side_effects = [];
|
||||
values.forEach(function(value, index) {
|
||||
value = fn(value, index);
|
||||
if (/]:|=/.test(value) ? canThrow && rng(10) == 0 : rng(5)) {
|
||||
declare_only.splice(rng(declare_only.length + 1), 0, value);
|
||||
} else if (canThrow && rng(5) == 0) {
|
||||
side_effects.splice(rng(side_effects.length + 1), 0, value);
|
||||
} else {
|
||||
side_effects.push(value);
|
||||
}
|
||||
});
|
||||
return declare_only.concat(side_effects);
|
||||
}
|
||||
|
||||
function convertToRest(names) {
|
||||
var last = names.length - 1;
|
||||
if (last >= 0 && SUPPORT.rest && rng(20) == 0) {
|
||||
var name = names[last];
|
||||
if (name && name.indexOf("=") < 0) {
|
||||
if (/^[[{]/.test(name)) name = "[ " + name + " ]";
|
||||
names[last] = "..." + name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fill(nameFn, valueFn) {
|
||||
var save_async = async;
|
||||
if (was_async != null) async = was_async;
|
||||
if (was_async != null) {
|
||||
async = false;
|
||||
if (save_async || was_async) addAvoidVar("await");
|
||||
}
|
||||
avoid.forEach(addAvoidVar);
|
||||
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||
var value = nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||
if (nameFn) nameFn();
|
||||
if (was_async != null) {
|
||||
async = was_async;
|
||||
if (save_async || was_async) removeAvoidVar("await");
|
||||
}
|
||||
if (valueFn) valueFn();
|
||||
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||
avoid.forEach(removeAvoidVar);
|
||||
async = save_async;
|
||||
return value;
|
||||
}
|
||||
|
||||
function createAssignmentValue(recurmax) {
|
||||
return nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||
}
|
||||
|
||||
function createDefaultValue(recurmax, noDefault) {
|
||||
return !noDefault && SUPPORT.default_value && rng(20) == 0 ? " = " + createAssignmentValue(recurmax) : "";
|
||||
}
|
||||
|
||||
function createKey(recurmax, keys) {
|
||||
@@ -459,20 +517,22 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
||||
return name;
|
||||
}
|
||||
|
||||
function createPairs(recurmax) {
|
||||
function createPairs(recurmax, noDefault) {
|
||||
var names = [], values = [];
|
||||
var m = rng(4), n = rng(4);
|
||||
if (!nameLenBefore) m = Math.max(m, n, 1);
|
||||
for (var i = Math.max(m, n); --i >= 0;) {
|
||||
if (i < m && i < n) {
|
||||
createDestructured(recurmax, names, values);
|
||||
continue;
|
||||
}
|
||||
if (i < m) {
|
||||
names.unshift(createName());
|
||||
}
|
||||
if (i < n) {
|
||||
values.unshift(createAssignmentValue(recurmax));
|
||||
createDestructured(recurmax, noDefault, names, values);
|
||||
} else if (i < m) {
|
||||
var name = createName();
|
||||
fill(function() {
|
||||
names.unshift(name + createDefaultValue(recurmax, noDefault));
|
||||
});
|
||||
} else {
|
||||
fill(null, function() {
|
||||
values.unshift(createAssignmentValue(recurmax));
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
@@ -481,7 +541,7 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
||||
};
|
||||
}
|
||||
|
||||
function createDestructured(recurmax, names, values) {
|
||||
function createDestructured(recurmax, noDefault, names, values) {
|
||||
switch (rng(20)) {
|
||||
case 0:
|
||||
if (--recurmax < 0) {
|
||||
@@ -489,20 +549,26 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
||||
values.unshift('""');
|
||||
} else {
|
||||
var pairs = createPairs(recurmax);
|
||||
while (!rng(10)) {
|
||||
var index = rng(pairs.names.length + 1);
|
||||
pairs.names.splice(index, 0, "");
|
||||
if (index < pairs.values.length) {
|
||||
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||
} else switch (rng(5)) {
|
||||
case 0:
|
||||
pairs.values[index] = createAssignmentValue(recurmax);
|
||||
case 1:
|
||||
pairs.values.length = index + 1;
|
||||
var default_value;
|
||||
fill(function() {
|
||||
default_value = createDefaultValue(recurmax, noDefault);
|
||||
}, function() {
|
||||
while (!rng(10)) {
|
||||
var index = rng(pairs.names.length + 1);
|
||||
pairs.names.splice(index, 0, "");
|
||||
if (index < pairs.values.length) {
|
||||
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||
} else switch (rng(5)) {
|
||||
case 0:
|
||||
pairs.values[index] = createAssignmentValue(recurmax);
|
||||
case 1:
|
||||
pairs.values.length = index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
||||
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||
convertToRest(pairs.names);
|
||||
names.unshift("[ " + pairs.names.join(", ") + " ]" + default_value);
|
||||
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -521,33 +587,38 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
||||
keys[index] = key;
|
||||
}
|
||||
});
|
||||
var save_async = async;
|
||||
if (was_async != null) {
|
||||
async = false;
|
||||
if (save_async || was_async) avoid.push("await");
|
||||
}
|
||||
addAvoidVars(avoid);
|
||||
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
|
||||
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
||||
return key ? key + ": " + name : name;
|
||||
}).join(", ")) + " }");
|
||||
if (was_async != null) {
|
||||
async = was_async;
|
||||
if (save_async || was_async) removeAvoidVars([ avoid.pop() ]);
|
||||
}
|
||||
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
|
||||
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||
return key + ": " + value;
|
||||
}).join(", ")) + " }");
|
||||
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||
removeAvoidVars(avoid);
|
||||
async = save_async;
|
||||
fill(function() {
|
||||
var last = pairs.names.length - 1, rest;
|
||||
if (last >= 0 && !(last in keys) && SUPPORT.rest_object && rng(20) == 0) {
|
||||
rest = pairs.names.pop();
|
||||
if (!/=/.test(rest)) rest = "..." + rest;
|
||||
}
|
||||
var s = mapShuffled(pairs.names, function(name, index) {
|
||||
if (index in keys) return keys[index] + ": " + name;
|
||||
return rng(10) == 0 ? name : createKey(recurmax, keys) + ": " + name;
|
||||
});
|
||||
if (rest) {
|
||||
s.push(rest);
|
||||
s = s.join(", ");
|
||||
} else {
|
||||
s = addTrailingComma(s.join(", "));
|
||||
}
|
||||
names.unshift("{ " + s + " }" + createDefaultValue(recurmax, noDefault));
|
||||
}, function() {
|
||||
values.unshift("{ " + addTrailingComma(mapShuffled(pairs.values, function(value, index) {
|
||||
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||
return key + ": " + value;
|
||||
}).join(", ")) + " }");
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
names.unshift(createName());
|
||||
values.unshift(createAssignmentValue(recurmax));
|
||||
var name = createName();
|
||||
fill(function() {
|
||||
names.unshift(name + createDefaultValue(recurmax, noDefault));
|
||||
}, function() {
|
||||
values.unshift(createAssignmentValue(recurmax));
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -575,8 +646,8 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||
}
|
||||
unique_vars.length -= 6;
|
||||
fn(function() {
|
||||
addAvoidVars(consts);
|
||||
addAvoidVars(lets);
|
||||
consts.forEach(addAvoidVar);
|
||||
lets.forEach(addAvoidVar);
|
||||
if (rng(2)) {
|
||||
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
|
||||
} else {
|
||||
@@ -610,17 +681,17 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||
default:
|
||||
s += names.map(function(name) {
|
||||
if (type == "let" && !rng(10)) {
|
||||
removeAvoidVars([ name ]);
|
||||
removeAvoidVar(name);
|
||||
return name;
|
||||
}
|
||||
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||
removeAvoidVars([ name ]);
|
||||
removeAvoidVar(name);
|
||||
return name + " = " + value;
|
||||
}).join(", ") + ";";
|
||||
names.length = 0;
|
||||
break;
|
||||
}
|
||||
removeAvoidVars(names);
|
||||
names.forEach(removeAvoidVar);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -659,8 +730,9 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
if (SUPPORT.destructuring && (!allowDefun || !(name in called)) && rng(2)) {
|
||||
called[name] = false;
|
||||
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
||||
params = addTrailingComma(pairs.names.join(", "));
|
||||
args = addTrailingComma(pairs.values.join(", "));
|
||||
params = pairs.names.join(", ");
|
||||
if (!pairs.has_rest) params = addTrailingComma(params);
|
||||
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
||||
} else {
|
||||
params = createParams(save_async);
|
||||
}
|
||||
@@ -682,10 +754,10 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
if (!allowDefun) {
|
||||
// avoid "function statements" (decl inside statements)
|
||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
||||
} else if (!(name in called) || args || rng(3)) {
|
||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
s += args || createArgs(recurmax, stmtDepth, canThrow);
|
||||
}
|
||||
|
||||
return s + ";";
|
||||
@@ -877,9 +949,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
unique_vars.length -= 6;
|
||||
if (SUPPORT.computed_key && rng(10) == 0) {
|
||||
s += " catch ({ message: " + message + ", ";
|
||||
addAvoidVars([ name ]);
|
||||
addAvoidVar(name);
|
||||
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
|
||||
removeAvoidVars([ name ]);
|
||||
removeAvoidVar(name);
|
||||
s += " }) { ";
|
||||
} else {
|
||||
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
|
||||
@@ -968,6 +1040,11 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
return rng(2) + " === 1 ? a : b";
|
||||
case p++:
|
||||
if (SUPPORT.template && rng(20) == 0) {
|
||||
var tmpl = createTemplateLiteral(recurmax, stmtDepth, canThrow);
|
||||
if (rng(10) == 0) tmpl = "String.raw" + tmpl;
|
||||
return tmpl;
|
||||
}
|
||||
case p++:
|
||||
return createValue();
|
||||
case p++:
|
||||
@@ -978,9 +1055,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case 0:
|
||||
return [
|
||||
"[ ",
|
||||
new Array(rng(3)).join(","),
|
||||
new Array(rng(3)).join(),
|
||||
getVarName(NO_CONST),
|
||||
new Array(rng(3)).join(","),
|
||||
new Array(rng(3)).join(),
|
||||
" ] = ",
|
||||
createArrayLiteral(recurmax, stmtDepth, canThrow),
|
||||
].join("");
|
||||
@@ -1011,7 +1088,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
var s = [];
|
||||
switch (rng(5)) {
|
||||
case 0:
|
||||
if (SUPPORT.arrow && !async && !name && rng(2)) {
|
||||
if (SUPPORT.arrow && !name && rng(2)) {
|
||||
var args, suffix;
|
||||
(rng(2) ? createBlockVariables : function() {
|
||||
arguments[3]();
|
||||
@@ -1019,21 +1096,23 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
var params;
|
||||
if (SUPPORT.destructuring && rng(2)) {
|
||||
var pairs = createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, save_async);
|
||||
params = addTrailingComma(pairs.names.join(", "));
|
||||
args = addTrailingComma(pairs.values.join(", "));
|
||||
params = pairs.names.join(", ");
|
||||
if (!pairs.has_rest) params = addTrailingComma(params);
|
||||
args = "(" + addTrailingComma(pairs.values.join(", ")) + ")";
|
||||
} else {
|
||||
params = createParams(save_async, NO_DUPLICATE);
|
||||
}
|
||||
params = (async ? "async (" : "(") + params + ") => ";
|
||||
if (defns) {
|
||||
s.push(
|
||||
"((" + params + ") => {",
|
||||
"(" + params + "{",
|
||||
strictMode(),
|
||||
defns(),
|
||||
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)
|
||||
);
|
||||
suffix = "})";
|
||||
} else {
|
||||
s.push("((" + params + ") => ");
|
||||
s.push("(" + params);
|
||||
switch (rng(10)) {
|
||||
case 0:
|
||||
s.push('(typeof arguments != "undefined" && arguments && arguments[' + rng(3) + "])");
|
||||
@@ -1051,7 +1130,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
async = save_async;
|
||||
VAR_NAMES.length = nameLenBefore;
|
||||
if (!args && rng(2)) args = createArgs(recurmax, stmtDepth, canThrow);
|
||||
if (args) suffix += "(" + args + ")";
|
||||
if (args) suffix += args;
|
||||
s.push(suffix);
|
||||
} else {
|
||||
s.push(
|
||||
@@ -1088,8 +1167,8 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
break;
|
||||
default:
|
||||
async = false;
|
||||
var instantiate = rng(4) ? "new " : "";
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
var instantiate = rng(4) ? "new " : "";
|
||||
s.push(
|
||||
instantiate + "function " + name + "(" + createParams(save_async) + "){",
|
||||
strictMode(),
|
||||
@@ -1103,7 +1182,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
});
|
||||
async = save_async;
|
||||
VAR_NAMES.length = nameLenBefore;
|
||||
s.push(rng(2) ? "}" : "}(" + createArgs(recurmax, stmtDepth, canThrow) + ")");
|
||||
s.push(rng(2) ? "}" : "}" + createArgs(recurmax, stmtDepth, canThrow, instantiate));
|
||||
break;
|
||||
}
|
||||
async = save_async;
|
||||
@@ -1181,7 +1260,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
var s = name + "." + getDotKey();
|
||||
s = "typeof " + s + ' == "function" && --_calls_ >= 0 && ' + s + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
s = "typeof " + s + ' == "function" && --_calls_ >= 0 && ' + s + createArgs(recurmax, stmtDepth, canThrow);
|
||||
return canThrow && rng(8) == 0 ? s : name + " && " + s;
|
||||
case p++:
|
||||
case p++:
|
||||
@@ -1192,7 +1271,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
||||
} while (name in called && !called[name]);
|
||||
called[name] = true;
|
||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + createArgs(recurmax, stmtDepth, canThrow);
|
||||
}
|
||||
_createExpression.N = p;
|
||||
return _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
@@ -1226,6 +1305,28 @@ function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
||||
return "[" + arr.join(", ") + "]";
|
||||
}
|
||||
|
||||
function createTemplateLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var s = [];
|
||||
addText();
|
||||
for (var i = rng(6); --i >= 0;) {
|
||||
s.push("${", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "}");
|
||||
addText();
|
||||
}
|
||||
return "`" + s.join(rng(5) ? "" : "\n") + "`";
|
||||
|
||||
function addText() {
|
||||
while (rng(5) == 0) s.push([
|
||||
" ",
|
||||
"$",
|
||||
"}",
|
||||
"\\`",
|
||||
"\\\\",
|
||||
"tmpl",
|
||||
][rng(6)]);
|
||||
}
|
||||
}
|
||||
|
||||
var SAFE_KEYS = [
|
||||
"length",
|
||||
"foo",
|
||||
@@ -1268,10 +1369,11 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
var save_async = async;
|
||||
var s;
|
||||
var name = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
switch (rng(SUPPORT.computed_key ? 3 : 2)) {
|
||||
case 0:
|
||||
async = false;
|
||||
var fn;
|
||||
switch (rng(SUPPORT.computed_key ? 3 : 2)) {
|
||||
case 0:
|
||||
async = false;
|
||||
fn = function(defns) {
|
||||
s = [
|
||||
"get " + name + "(){",
|
||||
strictMode(),
|
||||
@@ -1280,13 +1382,15 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||
"},",
|
||||
];
|
||||
break;
|
||||
case 1:
|
||||
var prop;
|
||||
do {
|
||||
prop = getDotKey();
|
||||
} while (name == prop);
|
||||
async = false;
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
var prop;
|
||||
do {
|
||||
prop = getDotKey();
|
||||
} while (name == prop);
|
||||
async = false;
|
||||
fn = function(defns) {
|
||||
s = [
|
||||
"set " + name + "(" + createVarName(MANDATORY) + "){",
|
||||
strictMode(),
|
||||
@@ -1295,9 +1399,11 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
"this." + prop + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||
"},",
|
||||
];
|
||||
break;
|
||||
default:
|
||||
async = SUPPORT.async && rng(50) == 0;
|
||||
};
|
||||
break;
|
||||
default:
|
||||
async = SUPPORT.async && rng(50) == 0;
|
||||
fn = function(defns) {
|
||||
s = [
|
||||
(async ? "async " : "") + name + "(" + createParams(save_async, NO_DUPLICATE) + "){",
|
||||
strictMode(),
|
||||
@@ -1305,9 +1411,10 @@ function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
"},",
|
||||
]
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
break;
|
||||
}
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, fn);
|
||||
async = save_async;
|
||||
VAR_NAMES.length = nameLenBefore;
|
||||
return filterDirective(s).join("\n");
|
||||
@@ -1441,18 +1548,26 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
function createTypeofExpr(recurmax, stmtDepth, canThrow) {
|
||||
switch (rng(8)) {
|
||||
case 0:
|
||||
return "(typeof " + createVarName(MANDATORY, DONT_STORE) + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
return "(typeof " + createVar() + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
case 1:
|
||||
return "(typeof " + createVarName(MANDATORY, DONT_STORE) + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
return "(typeof " + createVar() + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
case 2:
|
||||
return "(typeof " + createVarName(MANDATORY, DONT_STORE) + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
return "(typeof " + createVar() + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
case 3:
|
||||
return "(typeof " + createVarName(MANDATORY, DONT_STORE) + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
return "(typeof " + createVar() + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
|
||||
case 4:
|
||||
return "(typeof " + createVarName(MANDATORY, DONT_STORE) + ")";
|
||||
return "(typeof " + createVar() + ")";
|
||||
default:
|
||||
return "(typeof " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ")";
|
||||
}
|
||||
|
||||
function createVar() {
|
||||
var save_async = async;
|
||||
if (!async && avoid_vars.indexOf("await") >= 0) async = true;
|
||||
var name = createVarName(MANDATORY, DONT_STORE);
|
||||
async = save_async;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
function createValue() {
|
||||
@@ -1483,15 +1598,13 @@ function createUnaryPostfix() {
|
||||
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
||||
}
|
||||
|
||||
function addAvoidVars(names) {
|
||||
avoid_vars = avoid_vars.concat(names);
|
||||
function addAvoidVar(name) {
|
||||
avoid_vars.push(name);
|
||||
}
|
||||
|
||||
function removeAvoidVars(names) {
|
||||
names.forEach(function(name) {
|
||||
var index = avoid_vars.lastIndexOf(name);
|
||||
if (index >= 0) avoid_vars.splice(index, 1);
|
||||
});
|
||||
function removeAvoidVar(name) {
|
||||
var index = avoid_vars.lastIndexOf(name);
|
||||
if (index >= 0) avoid_vars.splice(index, 1);
|
||||
}
|
||||
|
||||
function getVarName(noConst) {
|
||||
@@ -1507,9 +1620,10 @@ function getVarName(noConst) {
|
||||
function createVarName(maybe, dontStore) {
|
||||
if (!maybe || rng(2)) {
|
||||
var suffix = rng(3);
|
||||
var name;
|
||||
var name, tries = 10;
|
||||
do {
|
||||
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||
if (--tries < 0) suffix++;
|
||||
if (suffix) name += "_" + suffix;
|
||||
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0 || async && name == "await");
|
||||
if (!dontStore) VAR_NAMES.push(name);
|
||||
@@ -1664,18 +1778,20 @@ function log(options) {
|
||||
}
|
||||
}
|
||||
errorln("//-------------------------------------------------------------");
|
||||
var reduce_options = JSON.parse(options);
|
||||
reduce_options.validate = true;
|
||||
var reduced = reduce_test(original_code, reduce_options, {
|
||||
verbose: false,
|
||||
}).code;
|
||||
if (reduced) {
|
||||
errorln();
|
||||
errorln("// reduced test case (output will differ)");
|
||||
errorln();
|
||||
errorln(reduced);
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
if (!ok) {
|
||||
var reduce_options = JSON.parse(options);
|
||||
reduce_options.validate = true;
|
||||
var reduced = reduce_test(original_code, reduce_options, {
|
||||
verbose: false,
|
||||
}).code;
|
||||
if (reduced) {
|
||||
errorln();
|
||||
errorln("// reduced test case (output will differ)");
|
||||
errorln();
|
||||
errorln(reduced);
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
}
|
||||
}
|
||||
errorln("minify(options):");
|
||||
errorln(JSON.stringify(JSON.parse(options), null, 2));
|
||||
@@ -1691,22 +1807,68 @@ function log(options) {
|
||||
}
|
||||
|
||||
function sort_globals(code) {
|
||||
var globals = sandbox.run_code("throw Object.keys(this).sort();" + code);
|
||||
return globals.length ? "var " + globals.join(",") + ";" + code : code;
|
||||
var globals = sandbox.run_code("throw Object.keys(this).sort(" + function(global) {
|
||||
return function(m, n) {
|
||||
return (n == "toString") - (m == "toString")
|
||||
|| (typeof global[n] == "function") - (typeof global[m] == "function")
|
||||
|| (m < n ? -1 : m > n ? 1 : 0);
|
||||
};
|
||||
} + "(this));" + code);
|
||||
if (!Array.isArray(globals)) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("//-------------------------------------------------------------");
|
||||
errorln("// !!! sort_globals() failed !!!");
|
||||
errorln("// expected Array, got:");
|
||||
if (!sandbox.is_error(globals)) try {
|
||||
globals = JSON.stringify(globals);
|
||||
} catch (e) {}
|
||||
errorln(globals);
|
||||
errorln("//");
|
||||
errorln(code);
|
||||
errorln();
|
||||
return code;
|
||||
}
|
||||
return globals.length ? "var " + globals.map(function(name) {
|
||||
return name + "=" + name;
|
||||
}).join() + ";" + code : code;
|
||||
}
|
||||
|
||||
function fuzzy_match(original, uglified) {
|
||||
uglified = uglified.split(" ");
|
||||
var i = uglified.length;
|
||||
original = original.split(" ", i);
|
||||
while (--i >= 0) {
|
||||
if (original[i] === uglified[i]) continue;
|
||||
var a = +original[i];
|
||||
var b = +uglified[i];
|
||||
if (Math.abs((b - a) / a) < 1e-10) continue;
|
||||
return false;
|
||||
var m = [], n = [];
|
||||
if (collect(original, m) !== collect(uglified, n)) return false;
|
||||
for (var i = 0; i < m.length; i++) {
|
||||
var a = m[i];
|
||||
var b = n[i];
|
||||
if (Math.abs((b - a) / a) > 1e-10) return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
function collect(input, nums) {
|
||||
return input.replace(/-?([1-9][0-9]*(\.[0-9]+)?|0\.[0-9]+)(e-?[1-9][0-9]*)?/ig, function(num) {
|
||||
return "<|" + nums.push(+num) + "|>";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function is_error_timeout(ex) {
|
||||
return /timed out/.test(ex.message);
|
||||
}
|
||||
|
||||
function is_error_in(ex) {
|
||||
return ex.name == "TypeError" && /'in'/.test(ex.message);
|
||||
}
|
||||
|
||||
function is_error_spread(ex) {
|
||||
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| is not a function/.test(ex.message);
|
||||
}
|
||||
|
||||
function is_error_recursion(ex) {
|
||||
return ex.name == "RangeError" && /Invalid string length|Maximum call stack size exceeded/.test(ex.message);
|
||||
}
|
||||
|
||||
function is_error_destructuring(ex) {
|
||||
return ex.name == "TypeError" && /^Cannot destructure /.test(ex.message);
|
||||
}
|
||||
|
||||
function patch_try_catch(orig, toplevel) {
|
||||
@@ -1716,6 +1878,7 @@ function patch_try_catch(orig, toplevel) {
|
||||
offset: 0,
|
||||
tries: [],
|
||||
} ];
|
||||
var tail_throw = '\nif (typeof UFUZZ_ERROR == "object") throw UFUZZ_ERROR;\n';
|
||||
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)[{]+)\)|}\s*finally)\s*(?={)/g;
|
||||
while (stack.length) {
|
||||
var code = stack[0].code;
|
||||
@@ -1732,7 +1895,7 @@ function patch_try_catch(orig, toplevel) {
|
||||
var insert;
|
||||
if (/}\s*finally\s*$/.test(match[0])) {
|
||||
tries.shift();
|
||||
insert = 'if (typeof UFUZZ_ERROR == "object") throw UFUZZ_ERROR;';
|
||||
insert = tail_throw;
|
||||
} else {
|
||||
while (tries.length && tries[0].catch) tries.shift();
|
||||
tries[0].catch = index - offset;
|
||||
@@ -1746,9 +1909,9 @@ function patch_try_catch(orig, toplevel) {
|
||||
"throw " + match[1] + ";",
|
||||
].join("\n");
|
||||
}
|
||||
var new_code = code.slice(0, index) + insert + code.slice(index);
|
||||
var new_code = code.slice(0, index) + insert + code.slice(index) + tail_throw;
|
||||
var result = sandbox.run_code(new_code, toplevel);
|
||||
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
|
||||
if (!sandbox.is_error(result)) {
|
||||
if (!stack.filled && match[1]) stack.push({
|
||||
code: code,
|
||||
index: index && index - 1,
|
||||
@@ -1757,15 +1920,18 @@ function patch_try_catch(orig, toplevel) {
|
||||
});
|
||||
offset += insert.length;
|
||||
code = new_code;
|
||||
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
|
||||
} else if (is_error_in(result)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
|
||||
} else if (result.name == "TypeError" && /not iterable/.test(result.message)) {
|
||||
} else if (is_error_spread(result)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("spread not iterable");' + orig.slice(index);
|
||||
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
|
||||
} else if (is_error_recursion(result)) {
|
||||
index = result.ufuzz_try;
|
||||
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
|
||||
} else if (is_error_destructuring(result)) {
|
||||
index = result.ufuzz_catch;
|
||||
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("cannot destructure");' + orig.slice(index);
|
||||
}
|
||||
}
|
||||
stack.filled = true;
|
||||
@@ -1781,6 +1947,18 @@ var beautify_options = {
|
||||
},
|
||||
};
|
||||
var minify_options = require("./options.json");
|
||||
if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") {
|
||||
minify_options.forEach(function(o) {
|
||||
if (!("mangle" in o)) o.mangle = {};
|
||||
if (o.mangle) o.mangle.v8 = true;
|
||||
});
|
||||
}
|
||||
var is_bug_async_arrow_rest = function() {};
|
||||
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && typeof sandbox.run_code("async (a = f(...[], b)) => 0;") != "string") {
|
||||
is_bug_async_arrow_rest = function(ex) {
|
||||
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
|
||||
};
|
||||
}
|
||||
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||
beautify_options.output.v8 = true;
|
||||
minify_options.forEach(function(o) {
|
||||
@@ -1799,6 +1977,8 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ];
|
||||
errored = typeof orig_result[0] != "string";
|
||||
if (errored) {
|
||||
println();
|
||||
println();
|
||||
println("//=============================================================");
|
||||
println("// original code");
|
||||
try_beautify(original_code, false, orig_result[0], println);
|
||||
@@ -1807,6 +1987,8 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
println("original result:");
|
||||
println(orig_result[0]);
|
||||
println();
|
||||
// ignore v8 parser bug
|
||||
if (is_bug_async_arrow_rest(orig_result[0])) continue;
|
||||
}
|
||||
minify_options.forEach(function(options) {
|
||||
var o = JSON.parse(options);
|
||||
@@ -1818,13 +2000,19 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
uglify_code = uglify_code.code;
|
||||
uglify_result = sandbox.run_code(uglify_code, toplevel);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
// ignore v8 parser bug
|
||||
if (!ok && is_bug_async_arrow_rest(uglify_result)) ok = true;
|
||||
// ignore declaration order of global variables
|
||||
if (!ok && !toplevel) {
|
||||
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
|
||||
}
|
||||
// ignore numerical imprecision caused by `unsafe_math`
|
||||
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == "string" && typeof uglify_result == "string") {
|
||||
ok = fuzzy_match(original_result, uglify_result);
|
||||
if (!ok && o.compress && o.compress.unsafe_math && typeof original_result == typeof uglify_result) {
|
||||
if (typeof original_result == "string") {
|
||||
ok = fuzzy_match(original_result, uglify_result);
|
||||
} else if (sandbox.is_error(original_result)) {
|
||||
ok = original_result.name == uglify_result.name && fuzzy_match(original_result.message, uglify_result.message);
|
||||
}
|
||||
if (!ok) {
|
||||
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
|
||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||
@@ -1832,14 +2020,29 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
}
|
||||
// ignore difference in error message caused by Temporal Dead Zone
|
||||
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
||||
// ignore spurious time-outs
|
||||
if (!ok && errored && /timed out/.test(original_result.message) && !/timed out/.test(uglify_result.message)) {
|
||||
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000);
|
||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||
if (!ok && errored && is_error_timeout(original_result)) {
|
||||
if (is_error_timeout(uglify_result)) {
|
||||
// ignore difference in error message
|
||||
ok = true;
|
||||
} else {
|
||||
// ignore spurious time-outs
|
||||
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000);
|
||||
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||
}
|
||||
}
|
||||
// ignore difference in error message caused by `in`
|
||||
if (!ok && errored && is_error_in(uglify_result) && is_error_in(original_result)) ok = true;
|
||||
// ignore difference in error message caused by spread syntax
|
||||
if (!ok && errored && is_error_spread(uglify_result) && is_error_spread(original_result)) ok = true;
|
||||
// ignore difference in depth of termination caused by infinite recursion
|
||||
if (!ok && errored && is_error_recursion(original_result)) {
|
||||
if (is_error_recursion(uglify_result) || typeof uglify_result == "string") ok = true;
|
||||
}
|
||||
// ignore difference in error message caused by destructuring
|
||||
if (!ok && errored && is_error_destructuring(uglify_result) && is_error_destructuring(original_result)) {
|
||||
ok = true;
|
||||
}
|
||||
// ignore errors above when caught by try-catch
|
||||
if (!ok) {
|
||||
var orig_skipped = patch_try_catch(original_code, toplevel);
|
||||
var uglify_skipped = patch_try_catch(uglify_code, toplevel);
|
||||
|
||||
@@ -70,7 +70,7 @@ function run() {
|
||||
|
||||
function trap(data) {
|
||||
stderr += data;
|
||||
if (~stderr.indexOf("\nminify(options):\n")) {
|
||||
if (~stderr.indexOf("!!!!!! Failed... round ")) {
|
||||
process.exitCode = 1;
|
||||
child.stderr.removeListener("data", trap);
|
||||
}
|
||||
|
||||
@@ -21,14 +21,16 @@
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"hoist_vars": true,
|
||||
"keep_infinity": true,
|
||||
"passes": 1e6,
|
||||
"unsafe": true
|
||||
},
|
||||
"keep_fnames": true,
|
||||
"toplevel": true
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"keep_fargs": false,
|
||||
"passes": 1e6,
|
||||
"sequences": 1e6,
|
||||
"unsafe": true,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// workaround for tty output truncation upon process.exit()
|
||||
var exit = process.exit;
|
||||
process.exit = function() {
|
||||
var args = [].slice.call(arguments);
|
||||
process.once("uncaughtException", function() {
|
||||
(function callback() {
|
||||
if (process.stdout.bufferSize || process.stderr.bufferSize) {
|
||||
setTimeout(callback, 1);
|
||||
} else {
|
||||
exit.apply(process, args);
|
||||
}
|
||||
})();
|
||||
});
|
||||
throw exit;
|
||||
};
|
||||
@@ -3,11 +3,11 @@ var fs = require("fs");
|
||||
exports.FILES = [
|
||||
require.resolve("../lib/utils.js"),
|
||||
require.resolve("../lib/ast.js"),
|
||||
require.resolve("../lib/parse.js"),
|
||||
require.resolve("../lib/transform.js"),
|
||||
require.resolve("../lib/parse.js"),
|
||||
require.resolve("../lib/scope.js"),
|
||||
require.resolve("../lib/output.js"),
|
||||
require.resolve("../lib/compress.js"),
|
||||
require.resolve("../lib/output.js"),
|
||||
require.resolve("../lib/sourcemap.js"),
|
||||
require.resolve("../lib/mozilla-ast.js"),
|
||||
require.resolve("../lib/propmangle.js"),
|
||||
@@ -23,6 +23,37 @@ new Function("exports", function() {
|
||||
return code.join("\n\n");
|
||||
}())(exports);
|
||||
|
||||
function to_comment(value) {
|
||||
if (typeof value != "string") value = JSON.stringify(value, function(key, value) {
|
||||
return typeof value == "function" ? "<[ " + value + " ]>" : value;
|
||||
}, 2);
|
||||
return "// " + value.replace(/\n/g, "\n// ");
|
||||
}
|
||||
|
||||
if (+process.env["UGLIFY_BUG_REPORT"]) exports.minify = function(files, options) {
|
||||
if (typeof options == "undefined") options = "<<undefined>>";
|
||||
var code = [
|
||||
"// UGLIFY_BUG_REPORT",
|
||||
to_comment(options),
|
||||
];
|
||||
if (typeof files == "string") {
|
||||
code.push("");
|
||||
code.push("//-------------------------------------------------------------")
|
||||
code.push("// INPUT CODE", files);
|
||||
} else for (var name in files) {
|
||||
code.push("");
|
||||
code.push("//-------------------------------------------------------------")
|
||||
code.push(to_comment(name), files[name]);
|
||||
}
|
||||
if (options.sourceMap && options.sourceMap.url) {
|
||||
code.push("");
|
||||
code.push("//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9");
|
||||
}
|
||||
var result = { code: code.join("\n") };
|
||||
if (options.sourceMap) result.map = '{"version":3,"sources":[],"names":[],"mappings":""}';
|
||||
return result;
|
||||
};
|
||||
|
||||
function describe_ast() {
|
||||
var out = OutputStream({ beautify: true });
|
||||
function doitem(ctor) {
|
||||
|
||||
22
tools/tty.js
Normal file
22
tools/tty.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// workaround for tty output truncation on Node.js
|
||||
try {
|
||||
// prevent buffer overflow and other asynchronous bugs
|
||||
process.stdout._handle.setBlocking(true);
|
||||
process.stderr._handle.setBlocking(true);
|
||||
} catch (e) {
|
||||
// ensure output buffers are flushed before process termination
|
||||
var exit = process.exit;
|
||||
process.exit = function() {
|
||||
var args = [].slice.call(arguments);
|
||||
process.once("uncaughtException", function() {
|
||||
(function callback() {
|
||||
if (process.stdout.bufferSize || process.stderr.bufferSize) {
|
||||
setTimeout(callback, 1);
|
||||
} else {
|
||||
exit.apply(process, args);
|
||||
}
|
||||
})();
|
||||
});
|
||||
throw exit;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user