Compare commits
207 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b10b93ee1 | ||
|
|
549de028b6 | ||
|
|
f579f1aa47 | ||
|
|
fcc40d0502 | ||
|
|
b309527264 | ||
|
|
5d19bb8d5d | ||
|
|
af97629912 | ||
|
|
8c000033d3 | ||
|
|
fd0d28e465 | ||
|
|
2123f38394 | ||
|
|
58dff9ada3 | ||
|
|
4fdec765bc | ||
|
|
1020d37256 | ||
|
|
076739db07 | ||
|
|
515e93d88a | ||
|
|
57105b299e | ||
|
|
77e1bda426 | ||
|
|
a59593cac8 | ||
|
|
046bbde9d4 | ||
|
|
fea9da9866 | ||
|
|
4733159782 | ||
|
|
5fba98608c | ||
|
|
c587d7917d | ||
|
|
336336f53f | ||
|
|
4bde50ce85 | ||
|
|
fbecedf94c | ||
|
|
2f31f95095 | ||
|
|
6b603e1a62 | ||
|
|
499f8d89ff | ||
|
|
9eb65f3af3 | ||
|
|
2cbbf5c375 | ||
|
|
3c384cf9a8 | ||
|
|
37f4f56752 | ||
|
|
1e4985ed9e | ||
|
|
d2d56e301e | ||
|
|
9d34f8428b | ||
|
|
f045e2b460 | ||
|
|
8791f258e3 | ||
|
|
af1cca25bf | ||
|
|
9b3a363604 | ||
|
|
1e8fa1aa1d | ||
|
|
9f67866147 | ||
|
|
645d5a348b | ||
|
|
cf120c7cea | ||
|
|
8d30902ba9 | ||
|
|
02459cddf9 | ||
|
|
1b579779be | ||
|
|
b18b70f63b | ||
|
|
641406d491 | ||
|
|
134ef0b1eb | ||
|
|
db87dcf13e | ||
|
|
aecbabc587 | ||
|
|
fd6544b340 | ||
|
|
f6a83f7944 | ||
|
|
35283e5dd1 | ||
|
|
7a51c17ff0 | ||
|
|
aff842f2f9 | ||
|
|
0bedd031da | ||
|
|
caa92aea5d | ||
|
|
383163afa6 | ||
|
|
8a83c8dd46 | ||
|
|
2a612fd472 | ||
|
|
b9798a01a8 | ||
|
|
6dbacb5e3f | ||
|
|
e5f80afc53 | ||
|
|
42e34c870a | ||
|
|
e390e7e124 | ||
|
|
6fd5b5b371 | ||
|
|
fba27bfb71 | ||
|
|
41310e6404 | ||
|
|
91fc1c82b5 | ||
|
|
810cd40356 | ||
|
|
1cbd07e789 | ||
|
|
b82de04775 | ||
|
|
4bbeb09f7c | ||
|
|
c2f6fd5fde | ||
|
|
af4ea3ff69 | ||
|
|
e7643248a3 | ||
|
|
68091dbf69 | ||
|
|
cbf7269296 | ||
|
|
d8563caba7 | ||
|
|
2e0ad40fe6 | ||
|
|
5d12abc41b | ||
|
|
79e5c3f564 | ||
|
|
607f87c5cd | ||
|
|
b2775746a7 | ||
|
|
e478da24c7 | ||
|
|
c5df8355ba | ||
|
|
ff38d2471f | ||
|
|
8e86d05c32 | ||
|
|
9e40abeded | ||
|
|
23ca7d675f | ||
|
|
fd8c0212b8 | ||
|
|
256950c2c0 | ||
|
|
8ecaa40c6e | ||
|
|
96bf7fceab | ||
|
|
6c7226c10e | ||
|
|
dc575919e2 | ||
|
|
4298201938 | ||
|
|
4f833937fe | ||
|
|
3d71e97dd1 | ||
|
|
7f35d9cee0 | ||
|
|
9f8106e1d8 | ||
|
|
b7b8435721 | ||
|
|
c0c04c33bb | ||
|
|
0e234a25c5 | ||
|
|
3096f6fdad | ||
|
|
176c09c6a5 | ||
|
|
9272f662c0 | ||
|
|
4d33cb2f94 | ||
|
|
00d0eda85b | ||
|
|
1cdf810f0b | ||
|
|
b512726cf3 | ||
|
|
9b7a13c8c7 | ||
|
|
74ff6ce261 | ||
|
|
b1b8898e7c | ||
|
|
55451e7b78 | ||
|
|
ffcce28ce1 | ||
|
|
9c0feb69e5 | ||
|
|
bc6e105174 | ||
|
|
b91a2459c0 | ||
|
|
b7a57fc69d | ||
|
|
2dbe40b01b | ||
|
|
813ac3ba96 | ||
|
|
220dc95c0d | ||
|
|
8f0521d51d | ||
|
|
f9946767c9 | ||
|
|
58ac5b9bd5 | ||
|
|
66140b459e | ||
|
|
1786c69070 | ||
|
|
95ef4d5377 | ||
|
|
04017215cc | ||
|
|
142bd1bd1a | ||
|
|
8cb509d50e | ||
|
|
baf4903aa7 | ||
|
|
35465d590e | ||
|
|
ccd91b9952 | ||
|
|
47a5e6e17a | ||
|
|
090ee895e1 | ||
|
|
1cd1a1e5ee | ||
|
|
1d835ac17d | ||
|
|
9e07ac4102 | ||
|
|
92d1391e5e | ||
|
|
b4ff6d0f2d | ||
|
|
9882a9f4af | ||
|
|
40f36b9e01 | ||
|
|
6e105c5ca6 | ||
|
|
af35cd32f2 | ||
|
|
7de8daa4b1 | ||
|
|
305a4bdcee | ||
|
|
3472cf1a90 | ||
|
|
6d4c0fa6fa | ||
|
|
3cca0d6249 | ||
|
|
12ac49b970 | ||
|
|
8c670cae93 | ||
|
|
0e3da27727 | ||
|
|
13cdc167a2 | ||
|
|
51803cdcb2 | ||
|
|
8fa470c17c | ||
|
|
90410f9fc3 | ||
|
|
ef3831437d | ||
|
|
171c544705 | ||
|
|
3c609e2f4a | ||
|
|
f0ae03ed39 | ||
|
|
31c6b45036 | ||
|
|
3ac533e644 | ||
|
|
38a46c86d7 | ||
|
|
0f0759ec15 | ||
|
|
7f501f9fed | ||
|
|
72844eb5a4 | ||
|
|
09d93cc6c8 | ||
|
|
dd1374aa8a | ||
|
|
fdf2e8c5b0 | ||
|
|
a9d934ab4e | ||
|
|
2a053710bd | ||
|
|
219aac6a84 | ||
|
|
2039185051 | ||
|
|
ad27c14202 | ||
|
|
a62b086184 | ||
|
|
335456cf77 | ||
|
|
d64d0b0bec | ||
|
|
3ac575f2e8 | ||
|
|
d33a3a3253 | ||
|
|
d7456a2dc2 | ||
|
|
d97672613d | ||
|
|
30761eede5 | ||
|
|
fb30aeccaf | ||
|
|
226aa1f76b | ||
|
|
6e235602fb | ||
|
|
980fcbb56b | ||
|
|
375ebe316d | ||
|
|
2500930234 | ||
|
|
2f0da2ff05 | ||
|
|
83a3cbf151 | ||
|
|
da8d154571 | ||
|
|
e33c727e8b | ||
|
|
f886b3fb2b | ||
|
|
b1cc15e85b | ||
|
|
3aa765e429 | ||
|
|
93d084a1d1 | ||
|
|
c7a3e09407 | ||
|
|
09525c7530 | ||
|
|
a7e15fe73c | ||
|
|
a31c27c7cf | ||
|
|
1caf7c7bd2 | ||
|
|
0eb0c9b388 | ||
|
|
7dc61cdc89 |
9
.github/workflows/ufuzz.yml
vendored
9
.github/workflows/ufuzz.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
env:
|
||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||
CAUSE: ${{ github.event_name }}
|
||||
RUN_NUM: ${{ github.run_number }}
|
||||
TOKEN: ${{ github.token }}
|
||||
jobs:
|
||||
ufuzz:
|
||||
@@ -36,12 +37,8 @@ jobs:
|
||||
npm config set update-notifier false
|
||||
npm --version
|
||||
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||
PERIOD=1800000
|
||||
if [[ $CAUSE == "schedule" ]]; then
|
||||
PERIOD=`node test/ufuzz/actions $BASE_URL $TOKEN`
|
||||
fi
|
||||
if (( $PERIOD == 0 )); then
|
||||
echo "too many jobs in queue - skipping..."
|
||||
node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM
|
||||
else
|
||||
node test/ufuzz/job $PERIOD
|
||||
node test/ufuzz/job 5000
|
||||
fi
|
||||
|
||||
49
README.md
49
README.md
@@ -4,10 +4,12 @@ UglifyJS 3
|
||||
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
||||
|
||||
#### Note:
|
||||
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
||||
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage)
|
||||
that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
||||
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS/tree/v2.x)**.
|
||||
- `uglify-js` only supports JavaScript (ECMAScript 5).
|
||||
- To minify ECMAScript 2015 or above, transpile using tools like [Babel](https://babeljs.io/).
|
||||
- `uglify-js` supports ECMAScript 5 and some newer language features.
|
||||
- To minify ECMAScript 2015 or above, you may need to transpile using tools like
|
||||
[Babel](https://babeljs.io/).
|
||||
|
||||
Install
|
||||
-------
|
||||
@@ -135,6 +137,10 @@ a double dash to prevent input files being used as option arguments:
|
||||
--toplevel Compress and/or mangle variables in top level scope.
|
||||
--verbose Print diagnostic messages.
|
||||
--warn Print warning messages.
|
||||
--webkit Support non-standard Safari/Webkit.
|
||||
Equivalent to setting `webkit: true` in `minify()`
|
||||
for `mangle` and `output` options.
|
||||
By default UglifyJS will not try to be Safari-proof.
|
||||
--wrap <name> Embed everything in a big function, making the
|
||||
“exports” and “global” variables available. You
|
||||
need to pass an argument to this option to
|
||||
@@ -519,6 +525,9 @@ if (result.error) throw result.error;
|
||||
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||
|
||||
- `webkit` (default `false`) -- enable workarounds for Safari/WebKit bugs.
|
||||
PhantomJS users should set this option to `true`.
|
||||
|
||||
## Minify options structure
|
||||
|
||||
```javascript
|
||||
@@ -688,6 +697,8 @@ to be `false` and all symbol names will be omitted.
|
||||
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
|
||||
when we can statically determine the condition.
|
||||
|
||||
- `merge_vars` (default: `true`) -- combine and reuse variables.
|
||||
|
||||
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
|
||||
where the return value is discarded, to avoid the parens that the
|
||||
code generator would insert.
|
||||
@@ -742,6 +753,8 @@ 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.
|
||||
|
||||
- `strings` (default: `true`) -- compact string concatenations.
|
||||
|
||||
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||
@@ -782,6 +795,9 @@ to be `false` and all symbol names will be omitted.
|
||||
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
|
||||
direct variable assignments do not count as references unless set to `"keep_assign"`)
|
||||
|
||||
- `varify` (default: `true`) -- convert block-scoped declaractions into `var`
|
||||
whenever safe to do so
|
||||
|
||||
## Mangle options
|
||||
|
||||
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
|
||||
@@ -863,6 +879,8 @@ can pass additional arguments that control the code output:
|
||||
}
|
||||
```
|
||||
|
||||
- `galio` (default `false`) -- enable workarounds for ANT Galio bugs
|
||||
|
||||
- `indent_level` (default `4`)
|
||||
|
||||
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
||||
@@ -901,8 +919,7 @@ can pass additional arguments that control the code output:
|
||||
|
||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||
|
||||
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
|
||||
PhantomJS users should set this option to `true`.
|
||||
- `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
|
||||
@@ -1133,7 +1150,7 @@ To enable fast minify mode with the API use:
|
||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||
```
|
||||
|
||||
#### Source maps and debugging
|
||||
### Source maps and debugging
|
||||
|
||||
Various `compress` transforms that simplify, rearrange, inline and remove code
|
||||
are known to have an adverse effect on debugging with source maps. This is
|
||||
@@ -1145,6 +1162,10 @@ disable the Uglify `compress` option and just use `mangle`.
|
||||
|
||||
To allow for better optimizations, the compiler makes various assumptions:
|
||||
|
||||
- The code does not rely on preserving its runtime performance characteristics.
|
||||
Typically uglified code will run faster due to less instructions and easier
|
||||
inlining, but may be slower on rare occasions for a specific platform, e.g.
|
||||
see [`reduce_funcs`](#compress-options).
|
||||
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
||||
objects they have not been overridden.
|
||||
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
||||
@@ -1156,6 +1177,18 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
- Object properties can be added, removed and modified (not prevented with
|
||||
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
||||
`Object.preventExtensions()` or `Object.seal()`).
|
||||
- Earlier versions of JavaScript will throw `SyntaxError` with the following:
|
||||
```js
|
||||
({
|
||||
p: 42,
|
||||
get p() {},
|
||||
});
|
||||
// SyntaxError: Object literal may not have data and accessor property with
|
||||
// the same name
|
||||
```
|
||||
UglifyJS may modify the input which in turn may suppress those errors.
|
||||
- Iteration order of keys over an object which contains spread syntax in later
|
||||
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
|
||||
@@ -1172,3 +1205,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
||||
top.B = "PASS";
|
||||
console.log(B);
|
||||
```
|
||||
- Use of `arguments` alongside destructuring as function parameters, e.g.
|
||||
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
|
||||
of Chrome and Node.js - UglifyJS may modify the input which in turn may
|
||||
suppress those errors.
|
||||
|
||||
19
bin/uglifyjs
19
bin/uglifyjs
@@ -111,6 +111,7 @@ function process_option(name, no_value) {
|
||||
" --validate Perform validation during AST manipulations.",
|
||||
" --verbose Print diagnostic messages.",
|
||||
" --warn Print warning messages.",
|
||||
" --webkit Support non-standard Safari/Webkit.",
|
||||
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
||||
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
||||
].join("\n"));
|
||||
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
|
||||
case "timings":
|
||||
case "toplevel":
|
||||
case "validate":
|
||||
case "webkit":
|
||||
options[name] = true;
|
||||
break;
|
||||
case "keep-fnames":
|
||||
@@ -276,7 +278,9 @@ function convert_ast(fn) {
|
||||
function run() {
|
||||
var content = options.sourceMap && options.sourceMap.content;
|
||||
if (content && content != "inline") {
|
||||
UglifyJS.AST_Node.info("Using input source map: " + content);
|
||||
UglifyJS.AST_Node.info("Using input source map: {content}", {
|
||||
content : content,
|
||||
});
|
||||
options.sourceMap.content = read_file(content, content);
|
||||
}
|
||||
try {
|
||||
@@ -342,7 +346,18 @@ function run() {
|
||||
}
|
||||
fatal(ex);
|
||||
} else if (output == "ast") {
|
||||
if (!options.compress && !options.mangle) result.ast.figure_out_scope({});
|
||||
if (!options.compress && !options.mangle) {
|
||||
var toplevel = result.ast;
|
||||
if (!(toplevel instanceof UglifyJS.AST_Toplevel)) {
|
||||
if (!(toplevel instanceof UglifyJS.AST_Statement)) toplevel = new UglifyJS.AST_SimpleStatement({
|
||||
body: toplevel,
|
||||
});
|
||||
toplevel = new UglifyJS.AST_Toplevel({
|
||||
body: [ toplevel ],
|
||||
});
|
||||
}
|
||||
toplevel.figure_out_scope({});
|
||||
}
|
||||
print(JSON.stringify(result.ast, function(key, value) {
|
||||
if (value) switch (key) {
|
||||
case "thedef":
|
||||
|
||||
387
lib/ast.js
387
lib/ast.js
@@ -137,17 +137,17 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||
}, null);
|
||||
|
||||
(AST_Node.log_function = function(fn, verbose) {
|
||||
var printed = Object.create(null);
|
||||
if (fn) {
|
||||
AST_Node.info = verbose ? function(text, props) {
|
||||
log("INFO: " + string_template(text, props));
|
||||
} : noop;
|
||||
AST_Node.warn = function(text, props) {
|
||||
log("WARN: " + string_template(text, props));
|
||||
};
|
||||
} else {
|
||||
if (!fn) {
|
||||
AST_Node.info = AST_Node.warn = noop;
|
||||
return;
|
||||
}
|
||||
var printed = Object.create(null);
|
||||
AST_Node.info = verbose ? function(text, props) {
|
||||
log("INFO: " + string_template(text, props));
|
||||
} : noop;
|
||||
AST_Node.warn = function(text, props) {
|
||||
log("WARN: " + string_template(text, props));
|
||||
};
|
||||
|
||||
function log(msg) {
|
||||
if (printed[msg]) return;
|
||||
@@ -203,9 +203,15 @@ var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
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_Statement && !(node[prop] instanceof AST_Function)) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -226,6 +232,34 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
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",
|
||||
},
|
||||
clone: function(deep) {
|
||||
var node = this._clone(deep);
|
||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||
if (this.functions) node.functions = this.functions.clone();
|
||||
if (this.variables) node.variables = this.variables.clone();
|
||||
return node;
|
||||
},
|
||||
pinned: function() {
|
||||
return this.resolve().pinned();
|
||||
},
|
||||
resolve: function() {
|
||||
return this.parent_scope.resolve();
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.parent_scope == null) return;
|
||||
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
||||
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
function walk_body(node, visitor) {
|
||||
node.body.forEach(function(node) {
|
||||
node.walk(visitor);
|
||||
@@ -246,19 +280,15 @@ var AST_Block = DEFNODE("Block", "body", {
|
||||
_validate: function() {
|
||||
this.body.forEach(function(node) {
|
||||
if (!(node instanceof AST_Statement)) throw new Error("body must be AST_Statement[]");
|
||||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
||||
if (is_function(node)) throw new Error("body cannot contain AST_Function");
|
||||
});
|
||||
},
|
||||
}, AST_Statement);
|
||||
}, AST_BlockScope);
|
||||
|
||||
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
||||
$documentation: "A block statement",
|
||||
}, AST_Block);
|
||||
|
||||
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
||||
$documentation: "The empty statement (empty block or simply a semicolon)"
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
||||
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
||||
$propdoc: {
|
||||
@@ -266,9 +296,9 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
||||
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
||||
if (is_function(this.body)) throw new Error("body cannot be AST_Function");
|
||||
},
|
||||
}, AST_Statement);
|
||||
}, AST_BlockScope);
|
||||
|
||||
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||
$documentation: "Statement with a label",
|
||||
@@ -288,10 +318,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||
var label = node.label;
|
||||
var def = this.label;
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
|
||||
if (node instanceof AST_LoopControl) {
|
||||
if (!node.label || node.label.thedef !== def) return;
|
||||
node.label.thedef = label;
|
||||
label.references.push(node);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) return true;
|
||||
}));
|
||||
}
|
||||
return node;
|
||||
@@ -357,7 +390,7 @@ var AST_For = DEFNODE("For", "init condition step", {
|
||||
if (this.init != null) {
|
||||
if (!(this.init instanceof AST_Node)) throw new Error("init must be AST_Node");
|
||||
if (this.init instanceof AST_Statement
|
||||
&& !(this.init instanceof AST_Definitions || this.init instanceof AST_Function)) {
|
||||
&& !(this.init instanceof AST_Definitions || is_function(this.init))) {
|
||||
throw new Error("init cannot be AST_Statement");
|
||||
}
|
||||
}
|
||||
@@ -383,8 +416,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
||||
_validate: function() {
|
||||
if (this.init instanceof AST_Definitions) {
|
||||
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
|
||||
} else if (!(this.init instanceof AST_PropAccess || this.init instanceof AST_SymbolRef)) {
|
||||
throw new Error("init must be assignable");
|
||||
} else {
|
||||
validate_destructured(this.init, function(node) {
|
||||
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||
throw new Error("init must be assignable: " + node.TYPE);
|
||||
}
|
||||
});
|
||||
}
|
||||
must_be_expression(this, "object");
|
||||
},
|
||||
@@ -409,32 +446,16 @@ var AST_With = DEFNODE("With", "expression", {
|
||||
|
||||
/* -----[ scope and functions ]----- */
|
||||
|
||||
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||
var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
|
||||
$documentation: "Base class for all statements introducing a lexical scope",
|
||||
$propdoc: {
|
||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
||||
},
|
||||
clone: function(deep) {
|
||||
var node = this._clone(deep);
|
||||
if (this.variables) node.variables = this.variables.clone();
|
||||
if (this.functions) node.functions = this.functions.clone();
|
||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||
return node;
|
||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||
},
|
||||
pinned: function() {
|
||||
return this.uses_eval || this.uses_with;
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.parent_scope != null) {
|
||||
if (!(this.parent_scope instanceof AST_Scope)) throw new Error("parent_scope must be AST_Scope");
|
||||
}
|
||||
},
|
||||
resolve: return_this,
|
||||
}, AST_Block);
|
||||
|
||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
@@ -481,12 +502,24 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
}
|
||||
}, AST_Scope);
|
||||
|
||||
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
||||
var AST_Lambda = DEFNODE("Lambda", "name argnames length_read uses_arguments", {
|
||||
$documentation: "Base class for functions",
|
||||
$propdoc: {
|
||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||
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_DestructuredKeyVal) {
|
||||
node.value.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolFunarg) visit(node);
|
||||
});
|
||||
this.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
@@ -500,7 +533,9 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
||||
},
|
||||
_validate: function() {
|
||||
this.argnames.forEach(function(node) {
|
||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||
validate_destructured(node, function(node) {
|
||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||
});
|
||||
});
|
||||
},
|
||||
}, AST_Scope);
|
||||
@@ -512,6 +547,19 @@ var AST_Accessor = DEFNODE("Accessor", null, {
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
function is_function(node) {
|
||||
return node instanceof AST_AsyncFunction || node instanceof AST_Function;
|
||||
}
|
||||
|
||||
var AST_AsyncFunction = DEFNODE("AsyncFunction", "inlined", {
|
||||
$documentation: "An asynchronous function expression",
|
||||
_validate: function() {
|
||||
if (this.name != null) {
|
||||
if (!(this.name instanceof AST_SymbolLambda)) throw new Error("name must be AST_SymbolLambda");
|
||||
}
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
var AST_Function = DEFNODE("Function", "inlined", {
|
||||
$documentation: "A function expression",
|
||||
_validate: function() {
|
||||
@@ -521,6 +569,17 @@ var AST_Function = DEFNODE("Function", "inlined", {
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
function is_defun(node) {
|
||||
return node instanceof AST_AsyncDefun || node instanceof AST_Defun;
|
||||
}
|
||||
|
||||
var AST_AsyncDefun = DEFNODE("AsyncDefun", "inlined", {
|
||||
$documentation: "An asynchronous function definition",
|
||||
_validate: function() {
|
||||
if (!(this.name instanceof AST_SymbolDefun)) throw new Error("name must be AST_SymbolDefun");
|
||||
},
|
||||
}, AST_Lambda);
|
||||
|
||||
var AST_Defun = DEFNODE("Defun", "inlined", {
|
||||
$documentation: "A function definition",
|
||||
_validate: function() {
|
||||
@@ -607,7 +666,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
|
||||
must_be_expression(this, "condition");
|
||||
if (this.alternative != null) {
|
||||
if (!(this.alternative instanceof AST_Statement)) throw new Error("alternative must be AST_Statement");
|
||||
if (this.alternative instanceof AST_Function) throw new error("alternative cannot be AST_Function");
|
||||
if (is_function(this.alternative)) throw new error("alternative cannot be AST_Function");
|
||||
}
|
||||
},
|
||||
}, AST_StatementWithBody);
|
||||
@@ -628,6 +687,9 @@ var AST_Switch = DEFNODE("Switch", "expression", {
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
this.body.forEach(function(node) {
|
||||
if (!(node instanceof AST_SwitchBranch)) throw new Error("body must be AST_SwitchBranch[]");
|
||||
});
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
@@ -685,17 +747,19 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||
$propdoc: {
|
||||
argname: "[AST_SymbolCatch] symbol for the exception"
|
||||
argname: "[AST_SymbolCatch?] symbol for the exception, or null if not present",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.argname.walk(visitor);
|
||||
if (node.argname) node.argname.walk(visitor);
|
||||
walk_body(node, visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||
if (this.argname != null) {
|
||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||
}
|
||||
},
|
||||
}, AST_Block);
|
||||
|
||||
@@ -717,14 +781,47 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
||||
defn.walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
_validate: function() {
|
||||
if (this.definitions.length < 1) throw new Error("must have at least one definition");
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_Const = DEFNODE("Const", null, {
|
||||
$documentation: "A `const` statement",
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||
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);
|
||||
|
||||
var AST_Let = DEFNODE("Let", null, {
|
||||
$documentation: "A `let` statement",
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||
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);
|
||||
|
||||
var AST_Var = DEFNODE("Var", null, {
|
||||
$documentation: "A `var` statement",
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||
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);
|
||||
@@ -742,18 +839,16 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
||||
if (node.value) node.value.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (!(this.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||
if (this.value != null) must_be_expression(this, "value");
|
||||
},
|
||||
});
|
||||
|
||||
/* -----[ OTHER ]----- */
|
||||
|
||||
function must_be_expressions(node, prop) {
|
||||
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 (node instanceof AST_Statement && !(node instanceof AST_Function)) {
|
||||
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");
|
||||
}
|
||||
});
|
||||
@@ -776,7 +871,7 @@ var AST_Call = DEFNODE("Call", "expression args pure", {
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
must_be_expressions(this, "args");
|
||||
must_be_expressions(this, "args", true);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -853,6 +948,22 @@ var AST_Sub = DEFNODE("Sub", null, {
|
||||
},
|
||||
}, AST_PropAccess);
|
||||
|
||||
var AST_Spread = DEFNODE("Spread", "expression", {
|
||||
$documentation: "Spread expression in array/object literals or function calls",
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] expression to be expanded",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Unary = DEFNODE("Unary", "operator expression", {
|
||||
$documentation: "Base class for unary expressions",
|
||||
$propdoc: {
|
||||
@@ -926,9 +1037,33 @@ var AST_Assign = DEFNODE("Assign", null, {
|
||||
$documentation: "An assignment expression — `a = b + 5`",
|
||||
_validate: function() {
|
||||
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
|
||||
if (this.left instanceof AST_Destructured) {
|
||||
if (this.operator != "=") throw new Error("invalid destructuring operator: " + this.operator);
|
||||
validate_destructured(this.left, function(node) {
|
||||
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||
throw new Error("left must be assignable: " + node.TYPE);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}, AST_Binary);
|
||||
|
||||
var AST_Await = DEFNODE("Await", "expression", {
|
||||
$documentation: "An await expression",
|
||||
$propdoc: {
|
||||
expression: "[AST_Node] expression with Promise to resolve on",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.expression.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expression(this, "expression");
|
||||
},
|
||||
});
|
||||
|
||||
/* -----[ LITERALS ]----- */
|
||||
|
||||
var AST_Array = DEFNODE("Array", "elements", {
|
||||
@@ -945,14 +1080,65 @@ var AST_Array = DEFNODE("Array", "elements", {
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
must_be_expressions(this, "elements");
|
||||
must_be_expressions(this, "elements", true, true);
|
||||
},
|
||||
});
|
||||
|
||||
var AST_Object = DEFNODE("Object", "properties", {
|
||||
$documentation: "An object literal",
|
||||
var AST_Destructured = DEFNODE("Destructured", null, {
|
||||
$documentation: "Base class for destructured literal",
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
check(node);
|
||||
}
|
||||
|
||||
var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
|
||||
$documentation: "A destructured array literal",
|
||||
$propdoc: {
|
||||
properties: "[AST_ObjectProperty*] array of properties"
|
||||
elements: "[AST_Node*] array of elements",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.elements.forEach(function(element) {
|
||||
element.walk(visitor);
|
||||
});
|
||||
});
|
||||
},
|
||||
}, AST_Destructured);
|
||||
|
||||
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",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||
node.value.walk(visitor);
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.key != "string") {
|
||||
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");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
|
||||
$documentation: "A destructured object literal",
|
||||
$propdoc: {
|
||||
properties: "[AST_DestructuredKeyVal*] array of properties",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
@@ -964,7 +1150,29 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
},
|
||||
_validate: function() {
|
||||
this.properties.forEach(function(node) {
|
||||
if (!(node instanceof AST_ObjectProperty)) throw new Error("properties must be AST_ObjectProperty[]");
|
||||
if (!(node instanceof AST_DestructuredKeyVal)) throw new Error("properties must be AST_DestructuredKeyVal[]");
|
||||
});
|
||||
},
|
||||
}, AST_Destructured);
|
||||
|
||||
var AST_Object = DEFNODE("Object", "properties", {
|
||||
$documentation: "An object literal",
|
||||
$propdoc: {
|
||||
properties: "[(AST_ObjectProperty|AST_Spread)*] array of properties"
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
node.properties.forEach(function(prop) {
|
||||
prop.walk(visitor);
|
||||
});
|
||||
});
|
||||
},
|
||||
_validate: function() {
|
||||
this.properties.forEach(function(node) {
|
||||
if (!(node instanceof AST_ObjectProperty || node instanceof AST_Spread)) {
|
||||
throw new Error("properties must contain AST_ObjectProperty and/or AST_Spread only");
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -972,24 +1180,28 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
$documentation: "Base class for literal object properties",
|
||||
$propdoc: {
|
||||
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
|
||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
|
||||
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||
node.value.walk(visitor);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
$documentation: "A key: value object property",
|
||||
$propdoc: {
|
||||
quote: "[string] the original quote character"
|
||||
},
|
||||
_validate: function() {
|
||||
if (typeof this.key != "string") throw new Error("key must be string");
|
||||
if (typeof this.key != "string") {
|
||||
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||
must_be_expression(this, "key");
|
||||
}
|
||||
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
||||
$documentation: "A key: value object property",
|
||||
_validate: function() {
|
||||
must_be_expression(this, "value");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -997,7 +1209,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
$documentation: "An object setter property",
|
||||
_validate: function() {
|
||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1005,31 +1216,34 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||
$documentation: "An object getter property",
|
||||
_validate: function() {
|
||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
|
||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||
$documentation: "Base class for all symbols",
|
||||
$propdoc: {
|
||||
name: "[string] name of this symbol",
|
||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||
},
|
||||
$documentation: "Base class for all symbols",
|
||||
_validate: function() {
|
||||
if (typeof this.name != "string") throw new Error("name must be string");
|
||||
},
|
||||
});
|
||||
|
||||
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
||||
$documentation: "The name of a property accessor (setter/getter function)"
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||
}, AST_Symbol);
|
||||
|
||||
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
||||
$documentation: "Symbol defining a constant",
|
||||
}, AST_SymbolDeclaration);
|
||||
|
||||
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
|
||||
$documentation: "Symbol defining a lexical-scoped variable",
|
||||
}, AST_SymbolDeclaration);
|
||||
|
||||
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
||||
$documentation: "Symbol defining a variable",
|
||||
}, AST_SymbolDeclaration);
|
||||
@@ -1237,14 +1451,13 @@ TreeWalker.prototype = {
|
||||
|| p.tail_node() === self) {
|
||||
self = p;
|
||||
} else if (p instanceof AST_Return) {
|
||||
var fn;
|
||||
do {
|
||||
fn = this.parent(++i);
|
||||
if (!fn) return false;
|
||||
} while (!(fn instanceof AST_Lambda));
|
||||
if (fn.name) return false;
|
||||
self = this.parent(++i);
|
||||
if (!self || self.TYPE != "Call" || self.expression !== fn) return false;
|
||||
for (var call, fn = p; call = this.parent(++i); fn = call) {
|
||||
if (call.TYPE == "Call") {
|
||||
if (!(fn instanceof AST_Lambda) || fn.name) return false;
|
||||
} else if (fn instanceof AST_Lambda) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
3157
lib/compress.js
3157
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,9 @@ function read_source_map(name, toplevel) {
|
||||
return to_ascii(match[2]);
|
||||
}
|
||||
}
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
AST_Node.warn("inline source map not found: {name}", {
|
||||
name: name,
|
||||
});
|
||||
}
|
||||
|
||||
function parse_source_map(content) {
|
||||
@@ -87,6 +89,7 @@ function minify(files, options) {
|
||||
toplevel: false,
|
||||
validate: false,
|
||||
warnings: false,
|
||||
webkit: false,
|
||||
wrap: false,
|
||||
}, true);
|
||||
if (options.validate) AST_Node.enable_validation();
|
||||
@@ -99,6 +102,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("webkit", options, [ "mangle", "output" ]);
|
||||
var quoted_props;
|
||||
if (options.mangle) {
|
||||
options.mangle = defaults(options.mangle, {
|
||||
@@ -109,6 +113,7 @@ function minify(files, options) {
|
||||
properties: false,
|
||||
reserved: [],
|
||||
toplevel: false,
|
||||
webkit: false,
|
||||
}, true);
|
||||
if (options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") {
|
||||
@@ -258,6 +263,7 @@ function minify(files, options) {
|
||||
} catch (ex) {
|
||||
return { error: ex };
|
||||
} finally {
|
||||
AST_Node.log_function();
|
||||
AST_Node.disable_validation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +115,6 @@
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
args.key = new AST_SymbolAccessor({
|
||||
name: args.key
|
||||
});
|
||||
args.value = new AST_Accessor(args.value);
|
||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||
@@ -385,7 +382,7 @@
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||
var key = {
|
||||
type: "Literal",
|
||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
||||
value: M.key
|
||||
};
|
||||
var kind;
|
||||
if (M instanceof AST_ObjectKeyVal) {
|
||||
|
||||
615
lib/output.js
615
lib/output.js
File diff suppressed because it is too large
Load Diff
546
lib/parse.js
546
lib/parse.js
@@ -44,21 +44,23 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
|
||||
var KEYWORDS_ATOM = 'false null true';
|
||||
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield'
|
||||
+ " " + KEYWORDS_ATOM + " " + KEYWORDS;
|
||||
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
|
||||
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof let new return switch throw try typeof var void while with";
|
||||
var KEYWORDS_ATOM = "false null true";
|
||||
var RESERVED_WORDS = [
|
||||
"await abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield",
|
||||
KEYWORDS_ATOM,
|
||||
KEYWORDS,
|
||||
].join(" ");
|
||||
var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
|
||||
|
||||
KEYWORDS = makePredicate(KEYWORDS);
|
||||
RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
||||
KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
|
||||
KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
|
||||
|
||||
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
|
||||
|
||||
var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
|
||||
var RE_OCT_NUMBER = /^0[0-7]+$/;
|
||||
var RE_BIN_NUMBER = /^0b([01]+)$/i;
|
||||
var RE_HEX_NUMBER = /^0x([0-9a-f]+)$/i;
|
||||
var RE_OCT_NUMBER = /^0o?([0-7]+)$/i;
|
||||
|
||||
var OPERATORS = makePredicate([
|
||||
"in",
|
||||
@@ -107,31 +109,21 @@ var OPERATORS = makePredicate([
|
||||
"||"
|
||||
]);
|
||||
|
||||
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF"));
|
||||
var NEWLINE_CHARS = "\n\r\u2028\u2029";
|
||||
var OPERATOR_CHARS = "+-*&%=<>!?|~^";
|
||||
var 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));
|
||||
|
||||
var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
|
||||
|
||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:"));
|
||||
|
||||
var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
|
||||
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
||||
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
||||
PUNC_BEFORE_EXPRESSION = makePredicate(characters(PUNC_BEFORE_EXPRESSION));
|
||||
PUNC_CHARS = makePredicate(characters(PUNC_CHARS));
|
||||
WHITESPACE_CHARS = makePredicate(characters(WHITESPACE_CHARS));
|
||||
|
||||
/* -----[ Tokenizer ]----- */
|
||||
|
||||
// regexps adapted from http://xregexp.com/plugins/#unicode
|
||||
var UNICODE = {
|
||||
letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
||||
digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]"),
|
||||
non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
||||
space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
||||
connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
||||
};
|
||||
|
||||
function is_letter(code) {
|
||||
return (code >= 97 && code <= 122)
|
||||
|| (code >= 65 && code <= 90)
|
||||
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
|
||||
}
|
||||
|
||||
function is_surrogate_pair_head(code) {
|
||||
return code >= 0xd800 && code <= 0xdbff;
|
||||
}
|
||||
@@ -144,36 +136,8 @@ function is_digit(code) {
|
||||
return code >= 48 && code <= 57;
|
||||
}
|
||||
|
||||
function is_alphanumeric_char(code) {
|
||||
return is_digit(code) || is_letter(code);
|
||||
}
|
||||
|
||||
function is_unicode_digit(code) {
|
||||
return UNICODE.digit.test(String.fromCharCode(code));
|
||||
}
|
||||
|
||||
function is_unicode_combining_mark(ch) {
|
||||
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
|
||||
}
|
||||
|
||||
function is_unicode_connector_punctuation(ch) {
|
||||
return UNICODE.connector_punctuation.test(ch);
|
||||
}
|
||||
|
||||
function is_identifier_start(code) {
|
||||
return code == 36 || code == 95 || is_letter(code);
|
||||
}
|
||||
|
||||
function is_identifier_char(ch) {
|
||||
var code = ch.charCodeAt(0);
|
||||
return is_identifier_start(code)
|
||||
|| is_digit(code)
|
||||
|| code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
|
||||
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
|
||||
|| is_unicode_combining_mark(ch)
|
||||
|| is_unicode_connector_punctuation(ch)
|
||||
|| is_unicode_digit(code)
|
||||
;
|
||||
return !NON_IDENTIFIER_CHARS[ch];
|
||||
}
|
||||
|
||||
function is_identifier_string(str) {
|
||||
@@ -181,14 +145,12 @@ function is_identifier_string(str) {
|
||||
}
|
||||
|
||||
function parse_js_number(num) {
|
||||
if (RE_HEX_NUMBER.test(num)) {
|
||||
return parseInt(num.substr(2), 16);
|
||||
} else if (RE_OCT_NUMBER.test(num)) {
|
||||
return parseInt(num.substr(1), 8);
|
||||
} else {
|
||||
var val = parseFloat(num);
|
||||
if (val == num) return val;
|
||||
}
|
||||
var match;
|
||||
if (match = RE_BIN_NUMBER.exec(num)) return parseInt(match[1], 2);
|
||||
if (match = RE_HEX_NUMBER.exec(num)) return parseInt(match[1], 16);
|
||||
if (match = RE_OCT_NUMBER.exec(num)) return parseInt(match[1], 8);
|
||||
var val = parseFloat(num);
|
||||
if (val == num) return val;
|
||||
}
|
||||
|
||||
function JS_Parse_Error(message, filename, line, col, pos) {
|
||||
@@ -344,11 +306,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
case (after_e = false, 46): // .
|
||||
return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
|
||||
}
|
||||
return is_alphanumeric_char(code);
|
||||
return is_digit(code) || /[_0-9a-fo]/i.test(ch);
|
||||
});
|
||||
if (prefix) num = prefix + num;
|
||||
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
||||
parse_error("Legacy octal literals are not allowed in strict mode");
|
||||
if (/^0[0-7_]+$/.test(num)) {
|
||||
if (next_token.has_directive("use strict")) parse_error("Legacy octal literals are not allowed in strict mode");
|
||||
} else {
|
||||
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);
|
||||
@@ -358,20 +322,30 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
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 : return String.fromCharCode(hex_bytes(4)); // \u
|
||||
case 10 : return ""; // newline
|
||||
case 13 : // \r
|
||||
if (peek() == "\n") { // DOS newline
|
||||
next(true, in_string);
|
||||
return "";
|
||||
}
|
||||
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
|
||||
}
|
||||
if (ch >= "0" && ch <= "7")
|
||||
return read_octal_escape_sequence(ch);
|
||||
@@ -438,7 +412,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
|
||||
var regex_allowed = S.regex_allowed;
|
||||
var i = find("*/", true);
|
||||
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
||||
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n");
|
||||
// update stream position
|
||||
forward(text.length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2);
|
||||
S.comments_before.push(token("comment2", text, true));
|
||||
@@ -448,7 +422,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function read_name() {
|
||||
var backslash = false, name = "", ch, escaped = false, hex;
|
||||
while ((ch = peek()) != null) {
|
||||
while (ch = peek()) {
|
||||
if (!backslash) {
|
||||
if (ch == "\\") escaped = backslash = true, next();
|
||||
else if (is_identifier_char(ch)) name += next();
|
||||
@@ -527,7 +501,16 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
function handle_dot() {
|
||||
next();
|
||||
return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
|
||||
var ch = peek();
|
||||
if (ch == ".") {
|
||||
var op = ".";
|
||||
do {
|
||||
op += ".";
|
||||
next();
|
||||
} while (peek() == ".");
|
||||
return token("operator", op);
|
||||
}
|
||||
return is_digit(ch.charCodeAt(0)) ? read_num(".") : token("punc", ".");
|
||||
}
|
||||
|
||||
function read_word() {
|
||||
@@ -587,7 +570,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
if (is_digit(code)) return read_num();
|
||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
||||
break;
|
||||
}
|
||||
parse_error("Unexpected character '" + ch + "'");
|
||||
@@ -670,13 +653,15 @@ function parse($TEXT, options) {
|
||||
input : typeof $TEXT == "string"
|
||||
? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang)
|
||||
: $TEXT,
|
||||
token : null,
|
||||
prev : null,
|
||||
peeked : null,
|
||||
in_function : 0,
|
||||
in_async : false,
|
||||
in_directives : true,
|
||||
in_funarg : -1,
|
||||
in_function : 0,
|
||||
in_loop : 0,
|
||||
labels : []
|
||||
labels : [],
|
||||
peeked : null,
|
||||
prev : null,
|
||||
token : null,
|
||||
};
|
||||
|
||||
S.token = next();
|
||||
@@ -779,7 +764,7 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
var statement = embed_tokens(function(strict_defun) {
|
||||
var statement = embed_tokens(function() {
|
||||
handle_regexp();
|
||||
switch (S.token.type) {
|
||||
case "string":
|
||||
@@ -803,9 +788,20 @@ function parse($TEXT, options) {
|
||||
return simple_statement();
|
||||
|
||||
case "name":
|
||||
return is_token(peek(), "punc", ":")
|
||||
? labeled_statement()
|
||||
: simple_statement();
|
||||
switch (S.token.value) {
|
||||
case "async":
|
||||
if (is_token(peek(), "keyword", "function")) {
|
||||
next();
|
||||
next();
|
||||
return function_(AST_AsyncDefun);
|
||||
}
|
||||
case "await":
|
||||
if (S.in_async) return simple_statement();
|
||||
default:
|
||||
return is_token(peek(), "punc", ":")
|
||||
? labeled_statement()
|
||||
: simple_statement();
|
||||
}
|
||||
|
||||
case "punc":
|
||||
switch (S.token.value) {
|
||||
@@ -832,6 +828,12 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return break_cont(AST_Break);
|
||||
|
||||
case "const":
|
||||
next();
|
||||
var node = const_();
|
||||
semicolon();
|
||||
return node;
|
||||
|
||||
case "continue":
|
||||
next();
|
||||
return break_cont(AST_Continue);
|
||||
@@ -864,9 +866,6 @@ function parse($TEXT, options) {
|
||||
return for_();
|
||||
|
||||
case "function":
|
||||
if (!strict_defun && S.input.has_directive("use strict")) {
|
||||
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
||||
}
|
||||
next();
|
||||
return function_(AST_Defun);
|
||||
|
||||
@@ -874,6 +873,12 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
return if_();
|
||||
|
||||
case "let":
|
||||
next();
|
||||
var node = let_();
|
||||
semicolon();
|
||||
return node;
|
||||
|
||||
case "return":
|
||||
if (S.in_function == 0 && !options.bare_returns)
|
||||
croak("'return' outside of function");
|
||||
@@ -988,14 +993,18 @@ function parse($TEXT, options) {
|
||||
expect("(");
|
||||
var init = null;
|
||||
if (!is("punc", ";")) {
|
||||
init = is("keyword", "var")
|
||||
init = is("keyword", "const")
|
||||
? (next(), const_(true))
|
||||
: is("keyword", "let")
|
||||
? (next(), let_(true))
|
||||
: is("keyword", "var")
|
||||
? (next(), var_(true))
|
||||
: expression(true, true);
|
||||
if (is("operator", "in")) {
|
||||
if (init instanceof AST_Var) {
|
||||
if (init instanceof AST_Definitions) {
|
||||
if (init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
} else if (!is_assignable(init)) {
|
||||
} else if (!(is_assignable(init) || (init = to_destructured(init)) instanceof AST_Destructured)) {
|
||||
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
}
|
||||
next();
|
||||
@@ -1030,19 +1039,27 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
var function_ = function(ctor) {
|
||||
var in_statement = ctor === AST_Defun;
|
||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||
if (in_statement && !name)
|
||||
expect_token("name");
|
||||
var was_async = S.in_async;
|
||||
var name;
|
||||
if (ctor === AST_AsyncDefun) {
|
||||
name = as_symbol(AST_SymbolDefun);
|
||||
S.in_async = true;
|
||||
} else if (ctor === AST_Defun) {
|
||||
name = as_symbol(AST_SymbolDefun);
|
||||
S.in_async = false;
|
||||
} else {
|
||||
S.in_async = ctor === AST_AsyncFunction;
|
||||
name = as_symbol(AST_SymbolLambda, true);
|
||||
}
|
||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||
unexpected(prev());
|
||||
expect("(");
|
||||
var argnames = [];
|
||||
for (var first = true; !is("punc", ")");) {
|
||||
if (first) first = false; else expect(",");
|
||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
||||
}
|
||||
next();
|
||||
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);
|
||||
});
|
||||
S.in_funarg = was_funarg;
|
||||
var loop = S.in_loop;
|
||||
var labels = S.labels;
|
||||
++S.in_function;
|
||||
@@ -1050,7 +1067,7 @@ function parse($TEXT, options) {
|
||||
S.input.push_directives_stack();
|
||||
S.in_loop = 0;
|
||||
S.labels = [];
|
||||
var body = block_(true);
|
||||
var body = block_();
|
||||
if (S.input.has_directive("use strict")) {
|
||||
if (name) strict_verify_symbol(name);
|
||||
argnames.forEach(strict_verify_symbol);
|
||||
@@ -1059,6 +1076,7 @@ function parse($TEXT, options) {
|
||||
--S.in_function;
|
||||
S.in_loop = loop;
|
||||
S.labels = labels;
|
||||
S.in_async = was_async;
|
||||
return new ctor({
|
||||
name: name,
|
||||
argnames: argnames,
|
||||
@@ -1079,12 +1097,12 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function block_(strict_defun) {
|
||||
function block_() {
|
||||
expect("{");
|
||||
var a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
a.push(statement(strict_defun));
|
||||
a.push(statement());
|
||||
}
|
||||
next();
|
||||
return a;
|
||||
@@ -1130,9 +1148,12 @@ function parse($TEXT, options) {
|
||||
if (is("keyword", "catch")) {
|
||||
var start = S.token;
|
||||
next();
|
||||
expect("(");
|
||||
var name = as_symbol(AST_SymbolCatch);
|
||||
expect(")");
|
||||
var name = null;
|
||||
if (is("punc", "(")) {
|
||||
next();
|
||||
name = as_symbol(AST_SymbolCatch);
|
||||
expect(")");
|
||||
}
|
||||
bcatch = new AST_Catch({
|
||||
start : start,
|
||||
argname : name,
|
||||
@@ -1158,13 +1179,22 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function vardefs(no_in) {
|
||||
function vardefs(type, no_in) {
|
||||
var a = [];
|
||||
for (;;) {
|
||||
var start = S.token;
|
||||
var name = maybe_destructured(type);
|
||||
var value = null;
|
||||
if (is("operator", "=")) {
|
||||
next();
|
||||
value = expression(false, no_in);
|
||||
} else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
|
||||
croak("Missing initializer in declaration");
|
||||
}
|
||||
a.push(new AST_VarDef({
|
||||
start : S.token,
|
||||
name : as_symbol(AST_SymbolVar),
|
||||
value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
|
||||
start : start,
|
||||
name : name,
|
||||
value : value,
|
||||
end : prev()
|
||||
}));
|
||||
if (!is("punc", ","))
|
||||
@@ -1174,10 +1204,26 @@ function parse($TEXT, options) {
|
||||
return a;
|
||||
}
|
||||
|
||||
var const_ = function(no_in) {
|
||||
return new AST_Const({
|
||||
start : prev(),
|
||||
definitions : vardefs(AST_SymbolConst, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
|
||||
var let_ = function(no_in) {
|
||||
return new AST_Let({
|
||||
start : prev(),
|
||||
definitions : vardefs(AST_SymbolLet, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
|
||||
var var_ = function(no_in) {
|
||||
return new AST_Var({
|
||||
start : prev(),
|
||||
definitions : vardefs(no_in),
|
||||
definitions : vardefs(AST_SymbolVar, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
@@ -1188,7 +1234,7 @@ function parse($TEXT, options) {
|
||||
var newexp = expr_atom(false), args;
|
||||
if (is("punc", "(")) {
|
||||
next();
|
||||
args = expr_list(")");
|
||||
args = expr_list(")", !options.strict);
|
||||
} else {
|
||||
args = [];
|
||||
}
|
||||
@@ -1206,7 +1252,7 @@ function parse($TEXT, options) {
|
||||
var tok = S.token, ret;
|
||||
switch (tok.type) {
|
||||
case "name":
|
||||
ret = _make_symbol(AST_SymbolRef);
|
||||
ret = _make_symbol(AST_SymbolRef, tok);
|
||||
break;
|
||||
case "num":
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
@@ -1280,9 +1326,16 @@ function parse($TEXT, options) {
|
||||
}
|
||||
unexpected();
|
||||
}
|
||||
if (is("keyword", "function")) {
|
||||
var ctor;
|
||||
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
|
||||
next();
|
||||
var func = function_(AST_Function);
|
||||
ctor = AST_AsyncFunction;
|
||||
} else if (is("keyword", "function")) {
|
||||
ctor = AST_Function;
|
||||
}
|
||||
if (ctor) {
|
||||
next();
|
||||
var func = function_(ctor);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
@@ -1293,15 +1346,22 @@ function parse($TEXT, options) {
|
||||
unexpected();
|
||||
};
|
||||
|
||||
function expr_list(closing, allow_trailing_comma, allow_empty) {
|
||||
function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
|
||||
if (!parser) parser = expression;
|
||||
var first = true, a = [];
|
||||
while (!is("punc", closing)) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (allow_trailing_comma && is("punc", closing)) break;
|
||||
if (is("punc", ",") && allow_empty) {
|
||||
if (allow_empty && is("punc", ",")) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
} else if (parser === expression && is("operator", "...")) {
|
||||
a.push(new AST_Spread({
|
||||
start: S.token,
|
||||
expression: (next(), parser()),
|
||||
end: prev(),
|
||||
}));
|
||||
} else {
|
||||
a.push(expression(false));
|
||||
a.push(parser());
|
||||
}
|
||||
}
|
||||
next();
|
||||
@@ -1324,51 +1384,71 @@ function parse($TEXT, options) {
|
||||
var first = true, a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (!options.strict && is("punc", "}"))
|
||||
// allow trailing comma
|
||||
break;
|
||||
// allow trailing comma
|
||||
if (!options.strict && is("punc", "}")) break;
|
||||
var start = S.token;
|
||||
var type = start.type;
|
||||
var name = as_property_name();
|
||||
if (type == "name" && !is("punc", ":")) {
|
||||
var key = new AST_SymbolAccessor({
|
||||
start: S.token,
|
||||
name: "" + as_property_name(),
|
||||
end: prev()
|
||||
});
|
||||
if (name == "get") {
|
||||
a.push(new AST_ObjectGetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (name == "set") {
|
||||
a.push(new AST_ObjectSetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (is("operator", "...")) {
|
||||
next();
|
||||
a.push(new AST_Spread({
|
||||
start: start,
|
||||
expression: expression(false),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
var key = as_property_key();
|
||||
if (is("punc", "(")) {
|
||||
var func_start = S.token;
|
||||
var func = function_(AST_Function);
|
||||
func.start = func_start;
|
||||
func.end = prev();
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: func,
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||
case "get":
|
||||
a.push(new AST_ObjectGetter({
|
||||
start: start,
|
||||
key: as_property_key(),
|
||||
value: create_accessor(),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
case "set":
|
||||
a.push(new AST_ObjectSetter({
|
||||
start: start,
|
||||
key: as_property_key(),
|
||||
value: create_accessor(),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
default:
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: _make_symbol(AST_SymbolRef, start),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : "" + name,
|
||||
value : expression(false),
|
||||
end : prev()
|
||||
start: start,
|
||||
key: key,
|
||||
value: expression(false),
|
||||
end: prev(),
|
||||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_Object({ properties: a });
|
||||
});
|
||||
|
||||
function as_property_name() {
|
||||
function as_property_key() {
|
||||
var tmp = S.token;
|
||||
switch (tmp.type) {
|
||||
case "operator":
|
||||
@@ -1379,7 +1459,13 @@ function parse($TEXT, options) {
|
||||
case "keyword":
|
||||
case "atom":
|
||||
next();
|
||||
return tmp.value;
|
||||
return "" + tmp.value;
|
||||
case "punc":
|
||||
if (tmp.value != "[") unexpected();
|
||||
next();
|
||||
var key = expression(false);
|
||||
expect("]");
|
||||
return key;
|
||||
default:
|
||||
unexpected();
|
||||
}
|
||||
@@ -1392,12 +1478,13 @@ function parse($TEXT, options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function _make_symbol(type) {
|
||||
var name = S.token.value;
|
||||
return new (name == "this" ? AST_This : type)({
|
||||
name : String(name),
|
||||
start : S.token,
|
||||
end : S.token
|
||||
function _make_symbol(type, token) {
|
||||
var name = token.value;
|
||||
if (name === "await" && S.in_async) unexpected(token);
|
||||
return new (name === "this" ? AST_This : type)({
|
||||
name: "" + name,
|
||||
start: token,
|
||||
end: token,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1411,7 +1498,7 @@ function parse($TEXT, options) {
|
||||
if (!noerror) croak("Name expected");
|
||||
return null;
|
||||
}
|
||||
var sym = _make_symbol(type);
|
||||
var sym = _make_symbol(type, S.token);
|
||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
||||
strict_verify_symbol(sym);
|
||||
}
|
||||
@@ -1419,6 +1506,54 @@ function parse($TEXT, options) {
|
||||
return sym;
|
||||
}
|
||||
|
||||
function maybe_destructured(type) {
|
||||
var start = S.token;
|
||||
if (is("punc", "[")) {
|
||||
next();
|
||||
return new AST_DestructuredArray({
|
||||
start: start,
|
||||
elements: expr_list("]", !options.strict, true, function() {
|
||||
return maybe_destructured(type);
|
||||
}),
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
if (is("punc", "{")) {
|
||||
next();
|
||||
var first = true, a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (first) first = false; else expect(",");
|
||||
// allow trailing comma
|
||||
if (!options.strict && is("punc", "}")) break;
|
||||
var key_start = S.token;
|
||||
var key = as_property_key();
|
||||
if (!is("punc", ":") && key_start.type == "name") {
|
||||
a.push(new AST_DestructuredKeyVal({
|
||||
start: key_start,
|
||||
key: key,
|
||||
value: _make_symbol(type, key_start),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
expect(":");
|
||||
a.push(new AST_DestructuredKeyVal({
|
||||
start: key_start,
|
||||
key: key,
|
||||
value: maybe_destructured(type),
|
||||
end: prev(),
|
||||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_DestructuredObject({
|
||||
start: start,
|
||||
properties: a,
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
return as_symbol(type);
|
||||
}
|
||||
|
||||
function mark_pure(call) {
|
||||
var start = call.start;
|
||||
var comments = start.comments_before;
|
||||
@@ -1459,7 +1594,7 @@ function parse($TEXT, options) {
|
||||
var call = new AST_Call({
|
||||
start : start,
|
||||
expression : expr,
|
||||
args : expr_list(")"),
|
||||
args : expr_list(")", !options.strict),
|
||||
end : prev()
|
||||
});
|
||||
mark_pure(call);
|
||||
@@ -1468,17 +1603,17 @@ function parse($TEXT, options) {
|
||||
return expr;
|
||||
};
|
||||
|
||||
var maybe_unary = function(allow_calls) {
|
||||
function maybe_unary() {
|
||||
var start = S.token;
|
||||
if (is("operator") && UNARY_PREFIX[start.value]) {
|
||||
next();
|
||||
handle_regexp();
|
||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
|
||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_await());
|
||||
ex.start = start;
|
||||
ex.end = prev();
|
||||
return ex;
|
||||
}
|
||||
var val = expr_atom(allow_calls);
|
||||
var val = expr_atom(true);
|
||||
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
|
||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||
val.start = start;
|
||||
@@ -1486,7 +1621,7 @@ function parse($TEXT, options) {
|
||||
next();
|
||||
}
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
function make_unary(ctor, token, expr) {
|
||||
var op = token.value;
|
||||
@@ -1504,13 +1639,26 @@ function parse($TEXT, options) {
|
||||
return new ctor({ operator: op, expression: expr });
|
||||
}
|
||||
|
||||
function maybe_await() {
|
||||
var start = S.token;
|
||||
if (!(S.in_async && is("name", "await"))) return maybe_unary();
|
||||
if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument");
|
||||
S.input.context().regex_allowed = true;
|
||||
next();
|
||||
return new AST_Await({
|
||||
start: start,
|
||||
expression: maybe_await(),
|
||||
end: prev(),
|
||||
});
|
||||
}
|
||||
|
||||
var expr_op = function(left, min_prec, no_in) {
|
||||
var op = is("operator") ? S.token.value : null;
|
||||
if (op == "in" && no_in) op = null;
|
||||
var prec = op != null ? PRECEDENCE[op] : null;
|
||||
if (prec != null && prec > min_prec) {
|
||||
next();
|
||||
var right = expr_op(maybe_unary(true), prec, no_in);
|
||||
var right = expr_op(maybe_await(), prec, no_in);
|
||||
return expr_op(new AST_Binary({
|
||||
start : left.start,
|
||||
left : left,
|
||||
@@ -1523,7 +1671,7 @@ function parse($TEXT, options) {
|
||||
};
|
||||
|
||||
function expr_ops(no_in) {
|
||||
return expr_op(maybe_unary(true), 0, no_in);
|
||||
return expr_op(maybe_await(), 0, no_in);
|
||||
}
|
||||
|
||||
var maybe_conditional = function(no_in) {
|
||||
@@ -1548,11 +1696,43 @@ function parse($TEXT, options) {
|
||||
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
||||
}
|
||||
|
||||
function to_destructured(node) {
|
||||
if (node instanceof AST_Array) {
|
||||
var elements = node.elements.map(to_destructured);
|
||||
return all(elements, function(node) {
|
||||
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
|
||||
}) ? new AST_DestructuredArray({
|
||||
start: node.start,
|
||||
elements: elements,
|
||||
end: node.end,
|
||||
}) : node;
|
||||
}
|
||||
if (!(node instanceof AST_Object)) 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;
|
||||
props.push(new AST_DestructuredKeyVal({
|
||||
start: prop.start,
|
||||
key: prop.key,
|
||||
value: value,
|
||||
end: prop.end,
|
||||
}));
|
||||
}
|
||||
return new AST_DestructuredObject({
|
||||
start: node.start,
|
||||
properties: props,
|
||||
end: node.end,
|
||||
});
|
||||
}
|
||||
|
||||
var maybe_assign = function(no_in) {
|
||||
var start = S.token;
|
||||
var left = maybe_conditional(no_in), val = S.token.value;
|
||||
if (is("operator") && ASSIGNMENT[val]) {
|
||||
if (is_assignable(left)) {
|
||||
if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
|
||||
next();
|
||||
return new AST_Assign({
|
||||
start : start,
|
||||
@@ -1600,7 +1780,7 @@ function parse($TEXT, options) {
|
||||
var body = [];
|
||||
S.input.push_directives_stack();
|
||||
while (!is("eof"))
|
||||
body.push(statement(true));
|
||||
body.push(statement());
|
||||
S.input.pop_directives_stack();
|
||||
var end = prev();
|
||||
var toplevel = options.toplevel;
|
||||
|
||||
@@ -81,8 +81,8 @@ var builtins = function() {
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node.quote) add(node.key);
|
||||
if (node instanceof AST_ObjectProperty) {
|
||||
if (node.start && node.start.quote) add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -110,7 +110,6 @@ function mangle_properties(ast, options) {
|
||||
cache: null,
|
||||
debug: false,
|
||||
keep_quoted: false,
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
reserved: null,
|
||||
}, true);
|
||||
@@ -166,11 +165,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
add(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
add(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter, since KeyVal is handled above
|
||||
add(node.key.name);
|
||||
if (typeof node.key == "string") add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -199,11 +195,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
node.property = mangle(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter
|
||||
node.key.name = mangle(node.key.name);
|
||||
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
if (!options.keep_quoted) mangleStrings(node.property);
|
||||
}
|
||||
@@ -213,7 +206,6 @@ function mangle_properties(ast, options) {
|
||||
|
||||
function can_mangle(name) {
|
||||
if (unmangleable[name]) return false;
|
||||
if (options.only_cache) return cache.has(name);
|
||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
383
lib/scope.js
383
lib/scope.js
@@ -59,6 +59,37 @@ function SymbolDef(id, scope, orig, init) {
|
||||
}
|
||||
|
||||
SymbolDef.prototype = {
|
||||
forEach: function(fn) {
|
||||
this.orig.forEach(fn);
|
||||
this.references.forEach(fn);
|
||||
},
|
||||
mangle: function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
if (this.global && cache && cache.has(this.name)) {
|
||||
this.mangled_name = cache.get(this.name);
|
||||
} else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||
var def = this.redefined();
|
||||
if (def) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else {
|
||||
this.mangled_name = next_mangled_name(this, options);
|
||||
}
|
||||
if (this.global && cache) {
|
||||
cache.set(this.name, this.mangled_name);
|
||||
}
|
||||
}
|
||||
},
|
||||
redefined: function() {
|
||||
var scope = this.defun;
|
||||
if (!scope) return;
|
||||
var name = this.name;
|
||||
var def = scope.variables.get(name)
|
||||
|| scope instanceof AST_Toplevel && scope.globals.get(name)
|
||||
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
|
||||
return def.name == name;
|
||||
}, scope.enclosed);
|
||||
if (def && def !== this) return def.redefined() || def;
|
||||
},
|
||||
unmangleable: function(options) {
|
||||
return this.global && !options.toplevel
|
||||
|| this.undeclared
|
||||
@@ -67,25 +98,6 @@ SymbolDef.prototype = {
|
||||
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||
|| this.orig[0] instanceof AST_SymbolDefun);
|
||||
},
|
||||
mangle: function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
if (this.global && cache && cache.has(this.name)) {
|
||||
this.mangled_name = cache.get(this.name);
|
||||
} else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||
var def;
|
||||
if (def = this.redefined()) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else {
|
||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
||||
}
|
||||
if (this.global && cache) {
|
||||
cache.set(this.name, this.mangled_name);
|
||||
}
|
||||
}
|
||||
},
|
||||
redefined: function() {
|
||||
return this.defun && this.defun.variables.get(this.name);
|
||||
}
|
||||
};
|
||||
|
||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
@@ -96,30 +108,46 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
|
||||
// pass 1: setup scope chaining and handle definitions
|
||||
var self = this;
|
||||
var scope = self.parent_scope = null;
|
||||
var defun = null;
|
||||
var next_def_id = 0;
|
||||
var scope = self.parent_scope = null;
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_Catch) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope.init_scope_vars(save_scope);
|
||||
descend();
|
||||
scope = save_scope;
|
||||
if (is_defun(node)) {
|
||||
node.name.walk(tw);
|
||||
walk_scope(function() {
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
walk_body(node, tw);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
node.init_scope_vars(scope);
|
||||
var save_scope = scope;
|
||||
var save_defun = defun;
|
||||
defun = scope = node;
|
||||
if (node instanceof AST_SwitchBranch) {
|
||||
node.init_vars(scope);
|
||||
descend();
|
||||
scope = save_scope;
|
||||
defun = save_defun;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Try) {
|
||||
walk_scope(function() {
|
||||
walk_body(node, tw);
|
||||
});
|
||||
if (node.bcatch) node.bcatch.walk(tw);
|
||||
if (node.bfinally) node.bfinally.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
|
||||
return;
|
||||
var s = scope;
|
||||
do {
|
||||
s = s.resolve();
|
||||
if (s.uses_with) break;
|
||||
s.uses_with = true;
|
||||
} while (s = s.parent_scope);
|
||||
walk_scope(descend);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_BlockScope) {
|
||||
walk_scope(descend);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Symbol) {
|
||||
node.scope = scope;
|
||||
@@ -128,60 +156,70 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
node.thedef = node;
|
||||
node.references = [];
|
||||
}
|
||||
if (node instanceof AST_SymbolDefun) {
|
||||
// This should be defined in the parent scope, as we encounter the
|
||||
// AST_Defun node before getting to its AST_Symbol.
|
||||
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
} else if (node instanceof AST_SymbolConst) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
} else if (node instanceof AST_SymbolDefun) {
|
||||
defun.def_function(node, tw.parent());
|
||||
entangle(defun, scope);
|
||||
} else if (node instanceof AST_SymbolFunarg) {
|
||||
defun.def_variable(node);
|
||||
entangle(defun, scope);
|
||||
} else if (node instanceof AST_SymbolLambda) {
|
||||
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||
} else if (node instanceof AST_SymbolLet) {
|
||||
scope.def_variable(node);
|
||||
} else if (node instanceof AST_SymbolVar) {
|
||||
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||
if (defun !== scope) {
|
||||
node.mark_enclosed(options);
|
||||
var def = scope.find_variable(node);
|
||||
if (node.thedef !== def) {
|
||||
node.thedef = def;
|
||||
}
|
||||
node.reference(options);
|
||||
}
|
||||
} else if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
defun.def_variable(node, null);
|
||||
entangle(defun, scope);
|
||||
}
|
||||
|
||||
function walk_scope(descend) {
|
||||
node.init_vars(scope);
|
||||
var save_defun = defun;
|
||||
var save_scope = scope;
|
||||
if (node instanceof AST_Scope) defun = node;
|
||||
scope = node;
|
||||
descend();
|
||||
scope = save_scope;
|
||||
defun = save_defun;
|
||||
}
|
||||
|
||||
function entangle(defun, scope) {
|
||||
if (defun === scope) return;
|
||||
node.mark_enclosed(options);
|
||||
var def = scope.find_variable(node.name);
|
||||
if (node.thedef === def) return;
|
||||
node.thedef = def;
|
||||
def.orig.push(node);
|
||||
node.mark_enclosed(options);
|
||||
}
|
||||
});
|
||||
self.next_def_id = 0;
|
||||
self.make_def = function(orig, init) {
|
||||
return new SymbolDef(++next_def_id, this, orig, init);
|
||||
};
|
||||
self.walk(tw);
|
||||
|
||||
// pass 2: find back references and eval
|
||||
self.globals = new Dictionary();
|
||||
var in_arg = [];
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Lambda) {
|
||||
in_arg.push(node);
|
||||
node.argnames.forEach(function(argname) {
|
||||
argname.walk(tw);
|
||||
});
|
||||
in_arg.pop();
|
||||
walk_body(node, tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_LoopControl) {
|
||||
if (node.label) node.label.thedef.references.push(node);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.name;
|
||||
var sym = node.scope.find_variable(name);
|
||||
if (!sym) {
|
||||
sym = self.def_global(node);
|
||||
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
||||
sym.scope.uses_arguments = true;
|
||||
}
|
||||
if (name == "eval") {
|
||||
var parent = tw.parent();
|
||||
if (parent.TYPE == "Call" && parent.expression === node) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||
s.uses_eval = true;
|
||||
}
|
||||
} else if (sym.undeclared) {
|
||||
self.uses_eval = true;
|
||||
}
|
||||
}
|
||||
node.thedef = sym;
|
||||
node.reference(options);
|
||||
return true;
|
||||
}
|
||||
// ensure mangling works if catch reuses a scope variable
|
||||
// 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) {
|
||||
@@ -190,6 +228,51 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.name;
|
||||
var sym = node.scope.find_variable(name);
|
||||
for (var i = in_arg.length; i > 0 && sym;) {
|
||||
i = in_arg.lastIndexOf(sym.scope, i - 1);
|
||||
if (i < 0) break;
|
||||
var decl = sym.orig[0];
|
||||
if (decl instanceof AST_SymbolFunarg || decl instanceof AST_SymbolLambda) {
|
||||
node.in_arg = true;
|
||||
break;
|
||||
}
|
||||
sym = sym.scope.parent_scope.find_variable(name);
|
||||
}
|
||||
if (!sym) {
|
||||
sym = self.def_global(node);
|
||||
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
||||
if (!(tw.parent() instanceof AST_PropAccess)) {
|
||||
sym.scope.uses_arguments = "d";
|
||||
} else if (!sym.scope.uses_arguments) {
|
||||
sym.scope.uses_arguments = true;
|
||||
}
|
||||
}
|
||||
if (name == "eval") {
|
||||
var parent = tw.parent();
|
||||
if (parent.TYPE == "Call" && parent.expression === node) {
|
||||
var s = node.scope;
|
||||
do {
|
||||
s = s.resolve();
|
||||
if (s.uses_eval) break;
|
||||
s.uses_eval = true;
|
||||
} while (s = s.parent_scope);
|
||||
} else if (sym.undeclared) {
|
||||
self.uses_eval = true;
|
||||
}
|
||||
}
|
||||
node.thedef = sym;
|
||||
node.reference(options);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
self.walk(tw);
|
||||
|
||||
@@ -218,10 +301,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
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;
|
||||
var new_def = scope.find_variable(name);
|
||||
if (new_def) {
|
||||
var redef;
|
||||
while (redef = new_def.redefined()) new_def = redef;
|
||||
var redef = new_def.redefined();
|
||||
if (redef) new_def = redef;
|
||||
} else {
|
||||
new_def = self.globals.get(name);
|
||||
}
|
||||
@@ -231,7 +317,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
new_def = scope.def_variable(node);
|
||||
}
|
||||
old_def.defun = new_def.scope;
|
||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||
old_def.forEach(function(node) {
|
||||
node.redef = true;
|
||||
node.thedef = new_def;
|
||||
node.reference(options);
|
||||
});
|
||||
@@ -240,12 +327,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("make_def", function(orig, init) {
|
||||
var top = this;
|
||||
while (top.parent_scope) top = top.parent_scope;
|
||||
return new SymbolDef(++top.next_def_id, this, orig, init);
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
var globals = this.globals, name = node.name;
|
||||
if (globals.has(name)) {
|
||||
@@ -259,24 +340,35 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
this.parent_scope = parent_scope; // the parent scope
|
||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
this.cname = -1; // the current index for mangling functions/variables
|
||||
});
|
||||
function init_block_vars(scope, parent) {
|
||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
||||
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
scope.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
if (parent) scope.make_def = parent.make_def; // top-level tracking of SymbolDef instances
|
||||
}
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
function init_scope_vars(scope, parent) {
|
||||
init_block_vars(scope, parent);
|
||||
scope.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
scope.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
}
|
||||
|
||||
AST_BlockScope.DEFMETHOD("init_vars", function(parent_scope) {
|
||||
init_block_vars(this, parent_scope);
|
||||
});
|
||||
AST_Scope.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;
|
||||
this.def_variable(new AST_SymbolFunarg({
|
||||
name: "arguments",
|
||||
start: this.start,
|
||||
end: this.end
|
||||
end: this.end,
|
||||
}));
|
||||
return this;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||
@@ -297,24 +389,23 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
|
||||
this.mark_enclosed(options);
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("find_variable", function(name) {
|
||||
if (name instanceof AST_Symbol) name = name.name;
|
||||
AST_BlockScope.DEFMETHOD("find_variable", function(name) {
|
||||
return this.variables.get(name)
|
||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||
|| this.parent_scope && this.parent_scope.find_variable(name);
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
|
||||
AST_BlockScope.DEFMETHOD("def_function", function(symbol, init) {
|
||||
var def = this.def_variable(symbol, init);
|
||||
if (!def.init || def.init instanceof AST_Defun) def.init = init;
|
||||
if (!def.init || is_defun(def.init)) def.init = init;
|
||||
this.functions.set(symbol.name, def);
|
||||
return def;
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
var def = this.variables.get(symbol.name);
|
||||
if (def) {
|
||||
def.orig.push(symbol);
|
||||
if (def.init instanceof AST_Function) def.init = init;
|
||||
if (is_function(def.init)) def.init = init;
|
||||
} else {
|
||||
def = this.make_def(symbol, init);
|
||||
this.variables.set(symbol.name, def);
|
||||
@@ -323,17 +414,12 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
return symbol.thedef = def;
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("resolve", return_this);
|
||||
AST_Scope.DEFMETHOD("resolve", function() {
|
||||
return this.parent_scope.resolve();
|
||||
});
|
||||
AST_Toplevel.DEFMETHOD("resolve", return_this);
|
||||
|
||||
function names_in_use(scope, options) {
|
||||
var names = scope.names_in_use;
|
||||
if (!names) {
|
||||
scope.names_in_use = names = Object.create(scope.mangled_names || null);
|
||||
scope.cname = -1;
|
||||
scope.cname_holes = [];
|
||||
scope.names_in_use = names = Object.create(null);
|
||||
var cache = options.cache && options.cache.props;
|
||||
scope.enclosed.forEach(function(def) {
|
||||
if (def.unmangleable(options)) names[def.name] = true;
|
||||
@@ -345,12 +431,13 @@ function names_in_use(scope, options) {
|
||||
return names;
|
||||
}
|
||||
|
||||
function next_mangled_name(scope, options, def) {
|
||||
function next_mangled_name(def, options) {
|
||||
var scope = def.scope;
|
||||
var in_use = names_in_use(scope, options);
|
||||
var holes = scope.cname_holes;
|
||||
var names = Object.create(null);
|
||||
var scopes = [ scope ];
|
||||
def.references.forEach(function(sym) {
|
||||
def.forEach(function(sym) {
|
||||
var scope = sym.scope;
|
||||
do {
|
||||
if (scopes.indexOf(scope) < 0) {
|
||||
@@ -366,7 +453,7 @@ function next_mangled_name(scope, options, def) {
|
||||
name = base54(holes[i]);
|
||||
if (names[name]) continue;
|
||||
holes.splice(i, 1);
|
||||
scope.names_in_use[name] = true;
|
||||
in_use[name] = true;
|
||||
return name;
|
||||
}
|
||||
while (true) {
|
||||
@@ -375,7 +462,7 @@ function next_mangled_name(scope, options, def) {
|
||||
if (!names[name]) break;
|
||||
holes.push(scope.cname);
|
||||
}
|
||||
scope.names_in_use[name] = true;
|
||||
in_use[name] = true;
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -387,18 +474,10 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
||||
// labels are always mangleable
|
||||
AST_Label.DEFMETHOD("unmangleable", return_false);
|
||||
|
||||
AST_Symbol.DEFMETHOD("unreferenced", function() {
|
||||
return !this.definition().references.length && !this.scope.pinned();
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("definition", function() {
|
||||
return this.thedef;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("global", function() {
|
||||
return this.definition().global;
|
||||
});
|
||||
|
||||
function _default_mangler_options(options) {
|
||||
options = defaults(options, {
|
||||
eval : false,
|
||||
@@ -406,6 +485,7 @@ function _default_mangler_options(options) {
|
||||
keep_fnames : false,
|
||||
reserved : [],
|
||||
toplevel : false,
|
||||
webkit : false,
|
||||
});
|
||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||
// Never mangle arguments
|
||||
@@ -424,7 +504,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
var lname = -1;
|
||||
|
||||
if (options.cache && options.cache.props) {
|
||||
var mangled_names = this.mangled_names = Object.create(null);
|
||||
var mangled_names = names_in_use(this, options);
|
||||
options.cache.props.each(function(mangled_name) {
|
||||
mangled_names[mangled_name] = true;
|
||||
});
|
||||
@@ -439,7 +519,26 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
lname = save_nesting;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
if (node instanceof AST_BlockScope) {
|
||||
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
||||
node.init.definitions.forEach(function(defn) {
|
||||
defn.name.match_symbol(function(sym) {
|
||||
if (!(sym instanceof AST_SymbolLet)) return;
|
||||
var def = sym.definition();
|
||||
var scope = sym.scope.parent_scope;
|
||||
var redef = scope.def_variable(sym);
|
||||
sym.thedef = def;
|
||||
scope.to_mangle.push(redef);
|
||||
def.redefined = function() {
|
||||
return redef;
|
||||
};
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
node.to_mangle = [];
|
||||
node.variables.each(function(def) {
|
||||
if (!defer_redef(def)) node.to_mangle.push(def);
|
||||
});
|
||||
descend();
|
||||
if (options.cache && node instanceof AST_Toplevel) {
|
||||
node.globals.each(mangle);
|
||||
@@ -449,9 +548,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
sym.scope = node;
|
||||
sym.reference(options);
|
||||
}
|
||||
node.variables.each(function(def) {
|
||||
if (!defer_redef(def)) mangle(def);
|
||||
});
|
||||
node.to_mangle.forEach(mangle);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Label) {
|
||||
@@ -462,13 +559,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
node.mangled_name = name;
|
||||
return true;
|
||||
}
|
||||
if (!options.ie8 && node instanceof AST_Catch) {
|
||||
var def = node.argname.definition();
|
||||
var redef = defer_redef(def, node.argname);
|
||||
descend();
|
||||
if (!redef) mangle(def);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
this.walk(tw);
|
||||
redefined.forEach(mangle);
|
||||
@@ -478,12 +568,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
def.mangle(options);
|
||||
}
|
||||
|
||||
function defer_redef(def, node) {
|
||||
function defer_redef(def) {
|
||||
var sym = def.orig[0];
|
||||
var redef = def.redefined();
|
||||
if (!redef) return false;
|
||||
if (!redef) {
|
||||
if (!(sym instanceof AST_SymbolConst)) return false;
|
||||
var scope = def.scope.resolve();
|
||||
if (def.scope === scope) return false;
|
||||
redef = scope.def_variable(sym);
|
||||
scope.to_mangle.push(redef);
|
||||
}
|
||||
redefined.push(def);
|
||||
def.references.forEach(reference);
|
||||
if (node) reference(node);
|
||||
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
||||
return true;
|
||||
|
||||
function reference(sym) {
|
||||
@@ -496,12 +593,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
|
||||
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
var avoid = Object.create(null);
|
||||
var avoid = Object.create(RESERVED_WORDS);
|
||||
options.reserved.forEach(to_avoid);
|
||||
this.globals.each(add_def);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(add_def);
|
||||
if (node instanceof AST_SymbolCatch) add_def(node.definition());
|
||||
if (node instanceof AST_BlockScope) node.variables.each(add_def);
|
||||
}));
|
||||
return avoid;
|
||||
|
||||
@@ -525,15 +621,14 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
var cname = 0;
|
||||
this.globals.each(rename);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(rename);
|
||||
if (node instanceof AST_SymbolCatch) rename(node.definition());
|
||||
if (node instanceof AST_BlockScope) node.variables.each(rename);
|
||||
}));
|
||||
|
||||
function next_name() {
|
||||
var name;
|
||||
do {
|
||||
name = base54(cname++);
|
||||
} while (avoid[name] || RESERVED_WORDS[name]);
|
||||
} while (avoid[name]);
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -544,7 +639,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
var redef = def.redefined();
|
||||
var name = redef ? redef.rename || redef.name : next_name();
|
||||
def.rename = name;
|
||||
def.orig.concat(def.references).forEach(function(sym) {
|
||||
def.forEach(function(sym) {
|
||||
if (sym.definition() === def) sym.name = name;
|
||||
});
|
||||
}
|
||||
@@ -558,8 +653,8 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
||||
options = _default_mangler_options(options);
|
||||
base54.reset();
|
||||
var fn = AST_Symbol.prototype.add_source_map;
|
||||
try {
|
||||
var fn = AST_Symbol.prototype.add_source_map;
|
||||
AST_Symbol.prototype.add_source_map = function() {
|
||||
if (!this.unmangleable(options)) base54.consider(this.name, -1);
|
||||
};
|
||||
|
||||
@@ -116,7 +116,7 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
|
||||
});
|
||||
DEF(AST_Catch, function(self, tw) {
|
||||
self.argname = self.argname.transform(tw);
|
||||
if (self.argname) self.argname = self.argname.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Definitions, function(self, tw) {
|
||||
@@ -138,6 +138,9 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
DEF(AST_Sequence, function(self, tw) {
|
||||
self.expressions = do_list(self.expressions, tw);
|
||||
});
|
||||
DEF(AST_Await, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Dot, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
@@ -145,6 +148,9 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.property = self.property.transform(tw);
|
||||
});
|
||||
DEF(AST_Spread, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Unary, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
@@ -160,10 +166,21 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
DEF(AST_Array, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
});
|
||||
DEF(AST_DestructuredArray, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
});
|
||||
DEF(AST_DestructuredKeyVal, function(self, tw) {
|
||||
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_DestructuredObject, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
DEF(AST_Object, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
DEF(AST_ObjectProperty, function(self, tw) {
|
||||
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
|
||||
57
lib/utils.js
57
lib/utils.js
@@ -112,51 +112,29 @@ function return_this() { return this; }
|
||||
function return_null() { return null; }
|
||||
|
||||
var List = (function() {
|
||||
function List(a, f, backwards) {
|
||||
var ret = [], top = [], i;
|
||||
function doit() {
|
||||
function List(a, f) {
|
||||
var ret = [];
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
var val = f(a[i], i);
|
||||
var is_last = val instanceof Last;
|
||||
if (is_last) val = val.v;
|
||||
if (val instanceof AtTop) {
|
||||
val = val.v;
|
||||
if (val instanceof Splice) {
|
||||
top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
top.push(val);
|
||||
}
|
||||
} else if (val !== skip) {
|
||||
if (val instanceof Splice) {
|
||||
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
ret.push(val);
|
||||
}
|
||||
}
|
||||
return is_last;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
if (backwards) {
|
||||
for (i = a.length; --i >= 0;) if (doit()) break;
|
||||
ret.reverse();
|
||||
top.reverse();
|
||||
if (val === skip) continue;
|
||||
if (val instanceof Splice) {
|
||||
ret.push.apply(ret, val.v);
|
||||
} else {
|
||||
for (i = 0; i < a.length; ++i) if (doit()) break;
|
||||
ret.push(val);
|
||||
}
|
||||
} else {
|
||||
for (i in a) if (HOP(a, i)) if (doit()) break;
|
||||
}
|
||||
return top.concat(ret);
|
||||
return ret;
|
||||
}
|
||||
List.is_op = function(val) {
|
||||
return val === skip || val instanceof AtTop || val instanceof Last || val instanceof Splice;
|
||||
return val === skip || val instanceof Splice;
|
||||
};
|
||||
List.splice = function(val) {
|
||||
return new Splice(val);
|
||||
};
|
||||
List.at_top = function(val) { return new AtTop(val); };
|
||||
List.splice = function(val) { return new Splice(val); };
|
||||
List.last = function(val) { return new Last(val); };
|
||||
var skip = List.skip = {};
|
||||
function AtTop(val) { this.v = val; }
|
||||
function Splice(val) { this.v = val; }
|
||||
function Last(val) { this.v = val; }
|
||||
function Splice(val) {
|
||||
this.v = val;
|
||||
}
|
||||
return List;
|
||||
})();
|
||||
|
||||
@@ -165,8 +143,9 @@ function push_uniq(array, el) {
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/\{(.+?)\}/g, function(str, p) {
|
||||
return props && props[p];
|
||||
return text.replace(/\{([^}]+)\}/g, function(str, p) {
|
||||
var value = props[p];
|
||||
return value instanceof AST_Node ? value.print_to_string() : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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.10.2",
|
||||
"version": "3.12.2",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,6 @@ function make_code(ast, options) {
|
||||
|
||||
function parse_test(file) {
|
||||
var script = fs.readFileSync(file, "utf8");
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
@@ -315,6 +314,7 @@ function test_case(test) {
|
||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||
}
|
||||
var output_code = make_code(output, output_options);
|
||||
U.AST_Node.log_function();
|
||||
if (expect != output_code) {
|
||||
log([
|
||||
"!!! failed",
|
||||
@@ -386,7 +386,7 @@ function test_case(test) {
|
||||
mangle: test.mangle
|
||||
});
|
||||
var actual = stdout[toplevel ? 1 : 0];
|
||||
if (test.expect_stdout === true) {
|
||||
if (test.expect_stdout === true || test.expect_stdout instanceof Error && test.expect_stdout.name === actual.name) {
|
||||
test.expect_stdout = actual;
|
||||
}
|
||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||
|
||||
@@ -783,3 +783,71 @@ issue_3420_7: {
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_4200: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: false,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
get p() {
|
||||
return arguments[0];
|
||||
},
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
get p() {
|
||||
return arguments[0];
|
||||
},
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4291_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
arguments[0] = "PASS";
|
||||
return arguments;
|
||||
}()[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
arguments[0] = "PASS";
|
||||
return arguments;
|
||||
}()[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4291_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
keep_fargs: "strict",
|
||||
}
|
||||
input: {
|
||||
var a = function() {
|
||||
if (arguments[0])
|
||||
arguments[1] = "PASS";
|
||||
return arguments;
|
||||
}(42);
|
||||
console.log(a[1], a[0], a.length);
|
||||
}
|
||||
expect: {
|
||||
var a = function(argument_0) {
|
||||
if (argument_0)
|
||||
arguments[1] = "PASS";
|
||||
return arguments;
|
||||
}(42);
|
||||
console.log(a[1], a[0], a.length);
|
||||
}
|
||||
expect_stdout: "PASS 42 1"
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
ascii_only_true: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only : true,
|
||||
ie8 : false,
|
||||
beautify : false,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "\x000\x001\x007\x008\x00" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||
}
|
||||
}
|
||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||
}
|
||||
|
||||
ascii_only_false: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only : false,
|
||||
ie8 : false,
|
||||
beautify : false,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "\x000\x001\x007\x008\x00" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||
}
|
||||
}
|
||||
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||
}
|
||||
@@ -76,9 +76,8 @@ asm_mixed: {
|
||||
start = start | 0;
|
||||
end = end | 0;
|
||||
var sum = 0.0, p = 0, q = 0;
|
||||
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
|
||||
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0)
|
||||
sum = sum + +log(values[p >> 3]);
|
||||
}
|
||||
return +sum;
|
||||
}
|
||||
function geometricMean(start, end) {
|
||||
@@ -91,11 +90,12 @@ asm_mixed: {
|
||||
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||
function logSum(start, end) {
|
||||
start |= 0, end |= 0;
|
||||
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
||||
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0)
|
||||
sum += +log(values[p >> 3]);
|
||||
return +sum;
|
||||
}
|
||||
function geometricMean(start, end) {
|
||||
return start |= 0, end |= 0, +exp(logSum(start, end) / (end - start | 0));
|
||||
return start |= 0, end |= 0, +exp(+logSum(start, end) / (end - start | 0));
|
||||
}
|
||||
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
|
||||
return { geometricMean: geometricMean };
|
||||
|
||||
498
test/compress/async.js
Normal file
498
test/compress/async.js
Normal file
@@ -0,0 +1,498 @@
|
||||
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"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
@@ -153,3 +153,31 @@ issue_3690: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4374: {
|
||||
options = {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
console.log(f());
|
||||
function f(a) {
|
||||
if (null) return 0;
|
||||
if (a) return 1;
|
||||
return 0;
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log(function(a) {
|
||||
return !null && a ? 1 : 0;
|
||||
}());
|
||||
})();
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
@@ -62,18 +62,18 @@ collapse_vars_side_effects_1: {
|
||||
expect: {
|
||||
function f1() {
|
||||
var s = "abcdef", i = 2;
|
||||
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
|
||||
console.log.bind(console)(s.charAt(i++), s.charAt(+i), s.charAt(4), 7);
|
||||
}
|
||||
function f2() {
|
||||
var s = "abcdef", i = 2;
|
||||
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(i++), 7);
|
||||
console.log.bind(console)(s.charAt(i++), 5, s.charAt(i++), s.charAt(+i), 7);
|
||||
}
|
||||
function f3() {
|
||||
var s = "abcdef",
|
||||
i = 2,
|
||||
log = console.log.bind(console),
|
||||
x = s.charAt(i++),
|
||||
y = s.charAt(i++);
|
||||
y = s.charAt(+i);
|
||||
log(x, s.charAt(4), y, 7);
|
||||
}
|
||||
function f4() {
|
||||
@@ -346,9 +346,8 @@ collapse_vars_if: {
|
||||
return "x" != "Bar" + x / 4 ? g9 : g5;
|
||||
}
|
||||
function f3(x) {
|
||||
if (x) {
|
||||
if (x)
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@@ -3073,7 +3072,6 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
0;
|
||||
try {
|
||||
!function(b) {
|
||||
(void 0)[1] = "foo";
|
||||
@@ -4193,9 +4191,8 @@ issue_2436_11: {
|
||||
if (isCollection(arg1)) {
|
||||
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
||||
return size && true === size.isMatrix ? matrix(res) : res;
|
||||
} else {
|
||||
} else
|
||||
return _randomInt(min = arg1, max = arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4311,9 +4308,8 @@ issue_2497: {
|
||||
function sample() {
|
||||
if (true)
|
||||
for (var i = 0; i < 1; ++i)
|
||||
for (var k = 0; k < 1; ++k) {
|
||||
for (var k = 0; k < 1; ++k)
|
||||
value = (value = 1) ? value + 1 : 0;
|
||||
}
|
||||
else
|
||||
for (i = 0; i < 1; ++i)
|
||||
for (k = 0; k < 1; ++k)
|
||||
@@ -8538,3 +8534,71 @@ issue_4051: {
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4070: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
function g() {}
|
||||
g.p++;
|
||||
return f.p = g.p;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
function g() {}
|
||||
return f.p = ++g.p;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4242: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
if (console)
|
||||
var a = function(){}, b = (!1 === console || a)();
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
console && (!1 === console || function(){})();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4248: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
try {
|
||||
a = 1;
|
||||
b[1];
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
try {
|
||||
a = 1;
|
||||
b[1];
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -238,6 +238,41 @@ concat_8: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_9: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
strings: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "foo";
|
||||
console.log(
|
||||
12 + (34 + a),
|
||||
null + (34 + a),
|
||||
12 + (null + a),
|
||||
false + (34 + a),
|
||||
12 + (false + a),
|
||||
"bar" + (34 + a),
|
||||
12 + ("bar" + a)
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
var a = "foo";
|
||||
console.log(
|
||||
"1234" + a,
|
||||
"null34" + a,
|
||||
"12null" + a,
|
||||
!1 + (34 + a),
|
||||
12 + (!1 + a),
|
||||
"bar34" + a,
|
||||
"12bar" + a
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3689: {
|
||||
options = {
|
||||
strings: true,
|
||||
|
||||
@@ -55,14 +55,15 @@ ifs_3_should_warn: {
|
||||
}
|
||||
input: {
|
||||
var x, y;
|
||||
if (x && !(x + "1") && y) { // 1
|
||||
// 1
|
||||
if (x && !(x + "1") && y) {
|
||||
var qq;
|
||||
foo();
|
||||
} else {
|
||||
bar();
|
||||
}
|
||||
|
||||
if (x || !!(x + "1") || y) { // 2
|
||||
// 2
|
||||
if (x || !!(x + "1") || y) {
|
||||
foo();
|
||||
} else {
|
||||
var jj;
|
||||
@@ -71,9 +72,25 @@ ifs_3_should_warn: {
|
||||
}
|
||||
expect: {
|
||||
var x, y;
|
||||
var qq; bar(); // 1
|
||||
var jj; foo(); // 2
|
||||
// 1
|
||||
var qq; bar();
|
||||
// 2
|
||||
foo(); var jj;
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: + in boolean context always true [test/compress/conditionals.js:3,18]",
|
||||
"WARN: Boolean && always false [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
||||
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
||||
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
||||
]
|
||||
}
|
||||
|
||||
ifs_4: {
|
||||
@@ -783,6 +800,28 @@ cond_12: {
|
||||
}
|
||||
}
|
||||
|
||||
cond_13: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
x ? y(a) : z(a);
|
||||
x ? y.f(a) : z.f(a);
|
||||
x ? y.f(a) : z.g(a);
|
||||
x ? y.f()(a) : z.g()(a);
|
||||
x ? y.f.u(a) : z.g.u(a);
|
||||
x ? y.f().u(a) : z.g().u(a);
|
||||
}
|
||||
expect: {
|
||||
(x ? y : z)(a);
|
||||
(x ? y : z).f(a);
|
||||
x ? y.f(a) : z.g(a);
|
||||
(x ? y.f() : z.g())(a);
|
||||
(x ? y.f : z.g).u(a);
|
||||
(x ? y.f() : z.g()).u(a);
|
||||
}
|
||||
}
|
||||
|
||||
ternary_boolean_consequent: {
|
||||
options = {
|
||||
booleans: true,
|
||||
@@ -1137,7 +1176,7 @@ issue_1645_2: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
condition_symbol_matches_consequent: {
|
||||
condition_matches_consequent: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
@@ -1166,6 +1205,35 @@ condition_symbol_matches_consequent: {
|
||||
expect_stdout: "3 7 true 4"
|
||||
}
|
||||
|
||||
condition_matches_alternative: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
function foo(x, y) {
|
||||
return x.p ? y[0] : x.p;
|
||||
}
|
||||
function bar() {
|
||||
return g ? h : g;
|
||||
}
|
||||
var g = 4;
|
||||
var h = 5;
|
||||
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
|
||||
}
|
||||
expect: {
|
||||
function foo(x, y) {
|
||||
return x.p && y[0];
|
||||
}
|
||||
function bar() {
|
||||
return g && h;
|
||||
}
|
||||
var g = 4;
|
||||
var h = 5;
|
||||
console.log(foo({ p: 3 }, [ null ]), foo({ p: 0 }, [ 7 ]), foo({ p: true } , [ false ]), bar());
|
||||
}
|
||||
expect_stdout: "null 0 false 5"
|
||||
}
|
||||
|
||||
delete_conditional_1: {
|
||||
options = {
|
||||
booleans: true,
|
||||
|
||||
1377
test/compress/const.js
Normal file
1377
test/compress/const.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,9 @@ dead_code_2_should_warn: {
|
||||
f();
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
||||
]
|
||||
node_version: "<=4"
|
||||
}
|
||||
|
||||
@@ -89,11 +92,21 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
function bar() {}
|
||||
// nothing for the while
|
||||
// as for the for, it should keep:
|
||||
var moo;
|
||||
var x = 10, y;
|
||||
var moo;
|
||||
bar();
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
||||
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
||||
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
||||
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
||||
]
|
||||
node_version: "<=4"
|
||||
}
|
||||
|
||||
@@ -1362,3 +1375,27 @@ issue_4051: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4366: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return "PASS";
|
||||
({
|
||||
p: 42,
|
||||
get p() {},
|
||||
});
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return "PASS";
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
1846
test/compress/destructured.js
Normal file
1846
test/compress/destructured.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1730,7 +1730,7 @@ chained_3: {
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
var c = b;
|
||||
b++;
|
||||
+b;
|
||||
return c;
|
||||
}(0, 2));
|
||||
}
|
||||
@@ -1997,7 +1997,7 @@ issue_3146_4: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3192: {
|
||||
issue_3192_1: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
@@ -2025,6 +2025,26 @@ issue_3192: {
|
||||
]
|
||||
}
|
||||
|
||||
issue_3192_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
(function(a) {
|
||||
console.log(a = "foo", arguments[0]);
|
||||
})("bar");
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
(function() {
|
||||
console.log("foo", arguments[0]);
|
||||
})("bar");
|
||||
}
|
||||
expect_stdout: "foo bar"
|
||||
}
|
||||
|
||||
issue_3233: {
|
||||
options = {
|
||||
pure_getters: "strict",
|
||||
@@ -2161,8 +2181,7 @@ issue_3515_1: {
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
this[c++] = 0;
|
||||
for (var key20 in !0);
|
||||
for (var key20 in !(this[c++] = 0));
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
@@ -2718,7 +2737,7 @@ issue_3962_1: {
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
}(1), 0);
|
||||
void 0;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -2751,7 +2770,7 @@ issue_3962_2: {
|
||||
0..toString();
|
||||
} while (0);
|
||||
if (c) console.log("PASS");
|
||||
}((a--, 1)), 0);
|
||||
}(1), 0);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -2834,11 +2853,11 @@ issue_4025: {
|
||||
console.log(a, b, d);
|
||||
}
|
||||
expect: {
|
||||
var d, c = 0;
|
||||
var c = 0;
|
||||
try {
|
||||
console.log(c);
|
||||
} finally {
|
||||
d = c + 1;
|
||||
var d = c + 1;
|
||||
c = 0;
|
||||
}
|
||||
console.log(1, 1, d);
|
||||
@@ -2848,3 +2867,248 @@ issue_4025: {
|
||||
"1 1 1",
|
||||
]
|
||||
}
|
||||
|
||||
forin_var_1: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var k;
|
||||
for (k in [ 1, 2 ])
|
||||
console.log(k);
|
||||
for (k in { PASS: 3 })
|
||||
console.log(k);
|
||||
console.log(k);
|
||||
}
|
||||
expect: {
|
||||
for (var k in [ 1, 2 ])
|
||||
console.log(k);
|
||||
for (k in { PASS: 3 })
|
||||
console.log(k);
|
||||
console.log(k);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"1",
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
forin_var_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
case function() {
|
||||
for (a in 0);
|
||||
}:
|
||||
var b = 0;
|
||||
}
|
||||
for (var c = 0; a;);
|
||||
var a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
switch (0) {
|
||||
case function() {
|
||||
for (a in 0);
|
||||
}:
|
||||
}
|
||||
for (; a;);
|
||||
var a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4133: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
merge_vars: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
var b = [ a-- ], c = b && b[c];
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
console.log(0);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4144: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a, b) {
|
||||
var b = console, c = ++b;
|
||||
})(console.log("PASS"), 0);
|
||||
}
|
||||
expect: {
|
||||
(function(b) {
|
||||
b = console,
|
||||
++b;
|
||||
})(console.log("PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4146: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b) {
|
||||
function g() {}
|
||||
var a = g;
|
||||
var c = b;
|
||||
c.p;
|
||||
console.log(typeof a);
|
||||
}
|
||||
f("FAIL", 42);
|
||||
}
|
||||
expect: {
|
||||
(function(a, b) {
|
||||
a = function () {};
|
||||
var c = b;
|
||||
c.p;
|
||||
console.log(typeof a);
|
||||
})(0, 42);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
var_catch_redefined: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw "PASS";
|
||||
} catch (a) {
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw "PASS";
|
||||
} catch (a) {
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
single_use_catch_redefined: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4184: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = function() {}, b = [ a, 1 && b, a = {} ];
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
{
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var b = [ function() {}, 1 && b, {} ];
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
console.log(a);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_4235: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
{
|
||||
const f = 0;
|
||||
}
|
||||
(function f() {
|
||||
var f = console.log(f);
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
f = console.log(f),
|
||||
void 0;
|
||||
var f;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -2869,3 +2869,208 @@ issue_4035: {
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4067: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
(function(b) {
|
||||
b[0] += 0;
|
||||
console.log(+a);
|
||||
})(a);
|
||||
})([]);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
(function(b) {
|
||||
b[0] += 0;
|
||||
console.log(+a);
|
||||
})(a);
|
||||
})([]);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4077: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log((a = []) - (a[0]++, 1) || "PASS");
|
||||
}
|
||||
expect: {
|
||||
console.log((a = []) - (a[0]++, 1) || "PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4119_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
b = a = [];
|
||||
a[0] += 0;
|
||||
if (+b + 1) {
|
||||
console.log("FAIL");
|
||||
} else {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
b = a = [];
|
||||
a[0] += 0;
|
||||
+b + 1 ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4119_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
(function(b) {
|
||||
a[0] += 0;
|
||||
console.log(+b + 1 ? "FAIL" : "PASS");
|
||||
})(a = []);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
(function(b) {
|
||||
a[0] += 0;
|
||||
console.log(+b + 1 ? "FAIL" : "PASS");
|
||||
})(a = []);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4119_3: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
b = a = {
|
||||
p: 42,
|
||||
};
|
||||
delete a.p;
|
||||
console.log(b.p ? "FAIL" : "PASS");
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
b = a = {
|
||||
p: 42,
|
||||
};
|
||||
delete a.p;
|
||||
console.log(b.p ? "FAIL" : "PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4119_4: {
|
||||
options = {
|
||||
booleans: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a, b;
|
||||
b = a = {
|
||||
p: 42,
|
||||
};
|
||||
delete a.p;
|
||||
console.log(!b ? "FAIL" : "PASS");
|
||||
}
|
||||
expect: {
|
||||
var a, b;
|
||||
b = a = {
|
||||
p: 42,
|
||||
};
|
||||
delete a.p;
|
||||
console.log((b, 0, "PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4214: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
return function() {
|
||||
try {
|
||||
return a;
|
||||
} finally {
|
||||
var b = 0;
|
||||
}
|
||||
}(a++ && this());
|
||||
}
|
||||
var c = f();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = function(a) {
|
||||
return function() {
|
||||
try {
|
||||
return a;
|
||||
} finally {}
|
||||
}(a++ && this());
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4271: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
p: null,
|
||||
q: (console.log("foo"), 42),
|
||||
p: function() {}
|
||||
})[console.log("bar"), "p"] && console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
p: null,
|
||||
q: (console.log("foo"), 42),
|
||||
p: function() {}
|
||||
})[console.log("bar"), "p"],
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ issue_2531_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
@@ -556,9 +556,10 @@ issue_2531_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -1483,8 +1484,7 @@ issue_2663_2: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var i;
|
||||
for (i in { a: 1, b: 2, c: 3 })
|
||||
for (var i in { a: 1, b: 2, c: 3 })
|
||||
j = i, console.log(j);
|
||||
var j;
|
||||
})();
|
||||
@@ -2082,7 +2082,7 @@ issue_3016_1: {
|
||||
var b = 1;
|
||||
do {
|
||||
3[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
@@ -2113,7 +2113,7 @@ issue_3016_2: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2146,7 +2146,7 @@ issue_3016_2_ie8: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2176,7 +2176,7 @@ issue_3016_3: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -2209,7 +2209,7 @@ issue_3016_3_ie8: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -2677,7 +2677,7 @@ cross_references_3: {
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math)(2));
|
||||
}()(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -3322,9 +3322,7 @@ issue_3506_1: {
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
!function(b) {
|
||||
b && (a = "PASS");
|
||||
}(a);
|
||||
a && (a = "PASS");
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -4778,3 +4776,450 @@ issue_4006: {
|
||||
}
|
||||
expect_stdout: "-1"
|
||||
}
|
||||
|
||||
issue_4155: {
|
||||
options = {
|
||||
functions: true,
|
||||
inline: true,
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
(function() {
|
||||
console.log(a);
|
||||
})(a);
|
||||
var b = function() {};
|
||||
b && console.log(typeof b);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
void console.log(b);
|
||||
var b = function() {};
|
||||
b && console.log(typeof b);
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"function",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4159: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 42, c = function(b) {
|
||||
(b = a) && console.log(a++, b);
|
||||
}(c = a);
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
(b = a) && console.log(a++, b);
|
||||
var b;
|
||||
}
|
||||
expect_stdout: "42 42"
|
||||
}
|
||||
|
||||
direct_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b) {
|
||||
function g(c) {
|
||||
return c >> 1;
|
||||
}
|
||||
return g(a) + g(b);
|
||||
}
|
||||
console.log(f(13, 31));
|
||||
}
|
||||
expect: {
|
||||
function f(a, b) {
|
||||
return (a >> 1) + (b >> 1);
|
||||
}
|
||||
console.log(f(13, 31));
|
||||
}
|
||||
expect_stdout: "21"
|
||||
}
|
||||
|
||||
direct_inline_catch_redefined: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
console.log(a, a, g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4171_1: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
while (a)
|
||||
var e = function() {};
|
||||
} catch (e) {
|
||||
return function() {
|
||||
return e;
|
||||
};
|
||||
}
|
||||
}(!console));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
while (a)
|
||||
var e = function() {};
|
||||
} catch (e) {
|
||||
return function() {
|
||||
return e;
|
||||
};
|
||||
}
|
||||
}(!console));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4171_2: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
while (a);
|
||||
} catch (e) {
|
||||
return function() {
|
||||
return e;
|
||||
};
|
||||
} finally {
|
||||
var e = function() {};
|
||||
}
|
||||
}(!console));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
while (a);
|
||||
} catch (e) {
|
||||
return function() {
|
||||
return e;
|
||||
};
|
||||
} finally {
|
||||
function e() {}
|
||||
}
|
||||
}(!console));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
catch_defun: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
function f() {
|
||||
return typeof a;
|
||||
}
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (o) {
|
||||
function t() {
|
||||
return typeof o;
|
||||
}
|
||||
}
|
||||
console.log(t());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
catch_no_argname: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
throw a;
|
||||
} catch {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
throw a;
|
||||
} catch {
|
||||
console.log(a, a, a);
|
||||
}
|
||||
console.log(a, a, a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS PASS PASS",
|
||||
"PASS PASS PASS",
|
||||
]
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
issue_4186: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
return function() {
|
||||
function f() {
|
||||
if (1)
|
||||
g();
|
||||
else
|
||||
(function() {
|
||||
return f;
|
||||
});
|
||||
}
|
||||
return f;
|
||||
function g() {
|
||||
if (1) {
|
||||
if (0)
|
||||
h;
|
||||
else
|
||||
h();
|
||||
var key = 0;
|
||||
}
|
||||
}
|
||||
function h() {
|
||||
return factory;
|
||||
}
|
||||
};
|
||||
}()());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
return function f() {
|
||||
1 ? void (1 && (0 ? h : h(), 0)) : function() {
|
||||
return f;
|
||||
};
|
||||
};
|
||||
function h() {
|
||||
return factory;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4233: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
try {
|
||||
var a = function() {};
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
(function() {
|
||||
console.log(typeof a);
|
||||
})();
|
||||
var a;
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
try {
|
||||
var a = function() {};
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
(function() {
|
||||
console.log(typeof a);
|
||||
})();
|
||||
var a;
|
||||
}
|
||||
} catch (e) {}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "number"
|
||||
}
|
||||
|
||||
issue_4259: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = function b() {
|
||||
var c = b;
|
||||
for (b in c);
|
||||
};
|
||||
a();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect: {
|
||||
function a() {
|
||||
for (a in a);
|
||||
}
|
||||
a();
|
||||
console.log(typeof a);
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_4261: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
(function() {
|
||||
function f() {
|
||||
e.p;
|
||||
}
|
||||
function g() {
|
||||
while (f());
|
||||
}
|
||||
(function() {
|
||||
while (console.log(g()));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (e) {
|
||||
(function() {
|
||||
function g() {
|
||||
while (void e.p);
|
||||
}
|
||||
(function() {
|
||||
while (console.log(g()));
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4265: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console;
|
||||
if ([ function() {
|
||||
return this + console.log(a);
|
||||
a;
|
||||
var a;
|
||||
}() ]);
|
||||
return 0;
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return console, function() {
|
||||
return console.log(a);
|
||||
var a;
|
||||
}(), 0;
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
trailing_comma: {
|
||||
input: {
|
||||
new function(a, b,) {
|
||||
console.log(b, a,);
|
||||
}(42, "PASS",);
|
||||
}
|
||||
expect_exact: 'new function(a,b){console.log(b,a)}(42,"PASS");'
|
||||
expect_stdout: "PASS 42"
|
||||
}
|
||||
|
||||
@@ -297,6 +297,33 @@ name_collision_3: {
|
||||
expect_stdout: "true 4 6"
|
||||
}
|
||||
|
||||
name_collision_4: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var o = {
|
||||
p: 0,
|
||||
q: "PASS",
|
||||
};
|
||||
return function(o_p) {
|
||||
if (!o.p) return o_p;
|
||||
}(o.q);
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o_p$0 = 0, o_q = "PASS";
|
||||
return function(o_p) {
|
||||
if (!o_p$0) return o_p;
|
||||
}(o_q);
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
contains_this_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
@@ -588,7 +588,6 @@ issue_3197_1: {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
var window = {};
|
||||
!function() {
|
||||
function Foo() {
|
||||
console.log(this instanceof Foo);
|
||||
@@ -598,7 +597,6 @@ issue_3197_1: {
|
||||
new window.Foo();
|
||||
}
|
||||
expect: {
|
||||
var window = {};
|
||||
window.Foo = function o() {
|
||||
console.log(this instanceof o);
|
||||
};
|
||||
@@ -619,7 +617,6 @@ issue_3197_1_ie8: {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
var window = {};
|
||||
!function() {
|
||||
function Foo() {
|
||||
console.log(this instanceof Foo);
|
||||
@@ -629,7 +626,6 @@ issue_3197_1_ie8: {
|
||||
new window.Foo();
|
||||
}
|
||||
expect: {
|
||||
var window = {};
|
||||
window.Foo = function Foo() {
|
||||
console.log(this instanceof Foo);
|
||||
};
|
||||
@@ -2714,3 +2710,193 @@ issue_2737: {
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
single_use_catch_redefined: {
|
||||
options = {
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
single_use_inline_catch_redefined: {
|
||||
options = {
|
||||
ie8: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
direct_inline_catch_redefined: {
|
||||
options = {
|
||||
ie8: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
throw 2;
|
||||
} catch (a) {
|
||||
function g() {
|
||||
return a;
|
||||
}
|
||||
console.log(a, f(), g());
|
||||
}
|
||||
console.log(a, a, g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4186: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {
|
||||
ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
(function NaN() {
|
||||
var a = 1;
|
||||
while (a--)
|
||||
try {} finally {
|
||||
console.log(0/0);
|
||||
var b;
|
||||
}
|
||||
})(f);
|
||||
}
|
||||
f();
|
||||
NaN;
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function NaN() {
|
||||
var n = 1;
|
||||
while (n--)
|
||||
console.log(0/0);
|
||||
})();
|
||||
})();
|
||||
NaN;
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4235: {
|
||||
options = {
|
||||
ie8: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {} catch (e) {}
|
||||
console.log(function e() {
|
||||
var e = 0;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
try {} catch (e) {}
|
||||
console.log(function e() {}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4250: {
|
||||
options = {
|
||||
ie8: true,
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
(function() {
|
||||
for (f in "f");
|
||||
})();
|
||||
return f;
|
||||
var f;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
(function() {
|
||||
for (f in "f");
|
||||
})();
|
||||
return f;
|
||||
var f;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
@@ -594,3 +594,157 @@ iife_if_return_simple: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
nested_if_break: {
|
||||
options = {
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
for (var i = 0; i < 3; i++)
|
||||
L1: if ("number" == typeof i) {
|
||||
if (0 === i) break L1;
|
||||
console.log(i);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
for (var i = 0; i < 3; i++)
|
||||
L1: if ("number" == typeof i)
|
||||
if (0 !== i) console.log(i);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
nested_if_continue: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
function f(n) {
|
||||
var i = 0;
|
||||
do {
|
||||
if ("number" == typeof n) {
|
||||
if (0 === n) {
|
||||
console.log("even", i);
|
||||
continue;
|
||||
}
|
||||
if (1 === n) {
|
||||
console.log("odd", i);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} while (0 <= (n -= 2));
|
||||
}
|
||||
f(37);
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
function f(n) {
|
||||
for (var i = 0;
|
||||
"number" == typeof n
|
||||
&& (0 !== n
|
||||
? 1 !== n
|
||||
? i++
|
||||
: console.log("odd", i)
|
||||
: console.log("even", i)),
|
||||
0 <= (n -= 2););
|
||||
}
|
||||
f(37);
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"odd 18",
|
||||
"even 21",
|
||||
]
|
||||
}
|
||||
|
||||
nested_if_return: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
if (A) {
|
||||
if (B)
|
||||
return B;
|
||||
if (C)
|
||||
return D;
|
||||
if (E)
|
||||
return F;
|
||||
if (G)
|
||||
return H;
|
||||
if (I) {
|
||||
if (J)
|
||||
return K;
|
||||
return;
|
||||
}
|
||||
if (L) {
|
||||
if (M)
|
||||
return;
|
||||
return N;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
if (A)
|
||||
return B || (C ? D : E ? F : G ? H : I ? J ? K : void 0 : L && !M ? N : void 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_866_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
sequences: false,
|
||||
};
|
||||
input: {
|
||||
function f(a) {
|
||||
if (a)
|
||||
return "";
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
if (a)
|
||||
return "";
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_866_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
if_return: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
if (a)
|
||||
if (b)
|
||||
c;
|
||||
else
|
||||
return d;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
if (a) {
|
||||
if (!b)
|
||||
return d;
|
||||
c;
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ non_hoisted_function_after_return: {
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -84,19 +84,16 @@ non_hoisted_function_after_return_2a: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 36",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||
"INFO: pass 1: last_count: 36, count: 18",
|
||||
"INFO: pass 1: last_count: 35, count: 18",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
]
|
||||
}
|
||||
@@ -242,19 +236,16 @@ non_hoisted_function_after_return_2a_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 47",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||
"INFO: pass 1: last_count: 47, count: 29",
|
||||
"INFO: pass 1: last_count: 46, count: 29",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ multiple_functions: {
|
||||
( function() {
|
||||
// NOTE: other compression steps will reduce this
|
||||
// down to just `window`.
|
||||
if ( window );
|
||||
if ( !window );
|
||||
function f() {}
|
||||
function g() {}
|
||||
} )();
|
||||
@@ -38,7 +38,7 @@ single_function: {
|
||||
}
|
||||
expect: {
|
||||
( function() {
|
||||
if ( window );
|
||||
if ( !window );
|
||||
function f() {}
|
||||
} )();
|
||||
}
|
||||
@@ -67,7 +67,7 @@ deeply_nested: {
|
||||
// NOTE: other compression steps will reduce this
|
||||
// down to just `window`.
|
||||
if ( window )
|
||||
if (document);
|
||||
if ( !document );
|
||||
function f() {}
|
||||
function g() {}
|
||||
function h() {}
|
||||
|
||||
@@ -151,15 +151,18 @@ Infinity_not_in_with_scope: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = { Infinity: 'oInfinity' };
|
||||
var o = { Infinity: "FAIL" };
|
||||
var vInfinity = "Infinity";
|
||||
vInfinity = Infinity;
|
||||
console.log(vInfinity);
|
||||
}
|
||||
expect: {
|
||||
var o = { Infinity: 'oInfinity' }
|
||||
var vInfinity = "Infinity"
|
||||
vInfinity = 1/0
|
||||
var o = { Infinity: "FAIL" };
|
||||
var vInfinity = "Infinity";
|
||||
vInfinity = 1/0;
|
||||
console.log(vInfinity);
|
||||
}
|
||||
expect_stdout: "Infinity"
|
||||
}
|
||||
|
||||
Infinity_in_with_scope: {
|
||||
@@ -167,15 +170,18 @@ Infinity_in_with_scope: {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = { Infinity: 'oInfinity' };
|
||||
var o = { Infinity: "PASS" };
|
||||
var vInfinity = "Infinity";
|
||||
with (o) { vInfinity = Infinity; }
|
||||
console.log(vInfinity);
|
||||
}
|
||||
expect: {
|
||||
var o = { Infinity: 'oInfinity' }
|
||||
var vInfinity = "Infinity"
|
||||
with (o) vInfinity = Infinity
|
||||
var o = { Infinity: "PASS" };
|
||||
var vInfinity = "Infinity";
|
||||
with (o) vInfinity = Infinity;
|
||||
console.log(vInfinity);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||
|
||||
@@ -277,8 +277,8 @@ join_object_assignments_forin: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var o = { a: "PASS" };
|
||||
for (var a in o)
|
||||
var o = { a: "PASS" }, a;
|
||||
for (a in o)
|
||||
return o[a];
|
||||
}());
|
||||
}
|
||||
|
||||
@@ -306,7 +306,6 @@ issue_2298: {
|
||||
expect: {
|
||||
!function() {
|
||||
(function() {
|
||||
0;
|
||||
try {
|
||||
!function() {
|
||||
(void 0)[1] = "foo";
|
||||
@@ -526,7 +525,7 @@ issue_2506: {
|
||||
function f0(bar) {
|
||||
(function() {
|
||||
(function() {
|
||||
if (false <= 0/0 & this >> 1 >= 0)
|
||||
if (false <= NaN & this >> 1 >= 0)
|
||||
c++;
|
||||
})(c++);
|
||||
})();
|
||||
@@ -1453,3 +1452,37 @@ issue_3619: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4353_1: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a) {}.length);
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {}.length);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_4353_2: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a) {
|
||||
while (console.log("PASS"));
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
while (console.log("PASS"));
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
1230
test/compress/let.js
Normal file
1230
test/compress/let.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -201,7 +201,7 @@ evaluate: {
|
||||
}
|
||||
}
|
||||
|
||||
issue_1532: {
|
||||
issue_1532_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
@@ -210,18 +210,56 @@ issue_1532: {
|
||||
function f(x, y) {
|
||||
do {
|
||||
if (x) break;
|
||||
foo();
|
||||
console.log(y);
|
||||
} while (false);
|
||||
}
|
||||
f(null, "PASS");
|
||||
f(42, "FAIL");
|
||||
}
|
||||
expect: {
|
||||
function f(x, y) {
|
||||
for (; !x && (console.log(y), false););
|
||||
}
|
||||
f(null, "PASS");
|
||||
f(42, "FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1532_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
function f(x, y) {
|
||||
do {
|
||||
if (x) {
|
||||
console.log(x);
|
||||
break;
|
||||
}
|
||||
console.log(y);
|
||||
} while (false);
|
||||
}
|
||||
f(null, "PASS");
|
||||
f(42, "FAIL");
|
||||
}
|
||||
expect: {
|
||||
function f(x, y) {
|
||||
do {
|
||||
if (x) break;
|
||||
foo();
|
||||
} while (false);
|
||||
if (x) {
|
||||
console.log(x);
|
||||
break;
|
||||
}
|
||||
} while (console.log(y), false);
|
||||
}
|
||||
f(null, "PASS");
|
||||
f(42, "FAIL");
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
}
|
||||
|
||||
issue_186: {
|
||||
@@ -509,8 +547,8 @@ dead_code_condition: {
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var c;
|
||||
var a = 0, b = 5;
|
||||
var c;
|
||||
a += 1, 0,
|
||||
console.log(a);
|
||||
}
|
||||
@@ -756,7 +794,37 @@ empty_for_in_side_effects: {
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:2,17]",
|
||||
]
|
||||
}
|
||||
|
||||
empty_for_in_prop_init: {
|
||||
options = {
|
||||
loops: true,
|
||||
pure_getters: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
var a = "bar";
|
||||
for ((a, f)[a] in console.log("foo"));
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a = "bar";
|
||||
console.log("foo");
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
expect_warnings: [
|
||||
"INFO: Dropping unused loop variable f [test/compress/loops.js:3,21]",
|
||||
"WARN: Side effects in object of for-in loop [test/compress/loops.js:3,30]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -933,3 +1001,282 @@ issue_3634_2: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_4075: {
|
||||
options = {
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
(function() {
|
||||
for (a in { PASS: 0 });
|
||||
})()
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
(function() {
|
||||
for (a in { PASS: 0 });
|
||||
})()
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4082: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
loops: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
(function(a) {
|
||||
for (a in "foo")
|
||||
var b;
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
(function(a) {
|
||||
for (a in "foo");
|
||||
})();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4084: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
loops: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
function f(a) {
|
||||
var b = a++;
|
||||
for (a in "foo");
|
||||
}
|
||||
f();
|
||||
return typeof a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
(function() {
|
||||
0;
|
||||
})();
|
||||
return typeof a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4091_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
for (var e in 42);
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4091_2: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
for (e in 42);
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
throw "FAIL";
|
||||
} catch (e) {
|
||||
var e;
|
||||
}
|
||||
console.log(e && e);
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
issue_4182_1: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
do {
|
||||
try {
|
||||
return;
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
console.log("FAIL");
|
||||
} while (0);
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
do {
|
||||
try {
|
||||
return;
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
console.log("FAIL");
|
||||
} while (0);
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4182_2: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
L: do {
|
||||
do {
|
||||
try {
|
||||
return;
|
||||
} finally {
|
||||
continue L;
|
||||
}
|
||||
console.log("FAIL");
|
||||
} while (0);
|
||||
console.log("FAIL");
|
||||
} while (0);
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
L: do {
|
||||
do {
|
||||
try {
|
||||
return;
|
||||
} finally {
|
||||
continue L;
|
||||
}
|
||||
} while (console.log("FAIL"), 0);
|
||||
console.log("FAIL");
|
||||
} while (0);
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
do_continue: {
|
||||
options = {
|
||||
loops: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
do {
|
||||
continue;
|
||||
} while ([ A ]);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
do {
|
||||
continue;
|
||||
} while ([ A ]);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4240: {
|
||||
options = {
|
||||
loops: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
function f() {
|
||||
var o = { PASS: 42 };
|
||||
for (a in o);
|
||||
}
|
||||
(function() {
|
||||
if (f());
|
||||
})();
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
(function() {
|
||||
if (function() {
|
||||
for (a in { PASS: 42 });
|
||||
}());
|
||||
})();
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4355: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
loops: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
while (function() {
|
||||
var a;
|
||||
for (a in console.log("PASS"))
|
||||
var b = 0;
|
||||
}())
|
||||
var c;
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
var c;
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
3185
test/compress/merge_vars.js
Normal file
3185
test/compress/merge_vars.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,100 @@
|
||||
hex_numbers_in_parentheses_for_prototype_functions: {
|
||||
parentheses_for_prototype_functions: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
(-2);
|
||||
(-2).toFixed(0);
|
||||
(function() {
|
||||
console.log((-2));
|
||||
console.log((-2).toFixed(0));
|
||||
|
||||
(2);
|
||||
(2).toFixed(0);
|
||||
console.log((2));
|
||||
console.log((2).toFixed(0));
|
||||
|
||||
(0.2);
|
||||
(0.2).toFixed(0);
|
||||
console.log((0.2));
|
||||
console.log((0.2).toFixed(0));
|
||||
|
||||
(2.34e20);
|
||||
(2.34e20).toFixed(0);
|
||||
console.log((2.34e20));
|
||||
console.log((2.34e20).toFixed(0));
|
||||
|
||||
(0.00000002);
|
||||
(0.00000002).toFixed(0);
|
||||
console.log((0.00000002));
|
||||
console.log((0.00000002).toFixed(0));
|
||||
|
||||
(1000000000000000128);
|
||||
(1000000000000000128).toFixed(0);
|
||||
console.log((1000000000000000128));
|
||||
console.log((1000000000000000128).toFixed(0));
|
||||
|
||||
(-1000000000000000128);
|
||||
(-1000000000000000128).toFixed(0);
|
||||
}
|
||||
console.log((-1000000000000000128));
|
||||
console.log((-1000000000000000128).toFixed(0));
|
||||
})();
|
||||
}
|
||||
expect_exact: [
|
||||
"function f() {",
|
||||
" -2;",
|
||||
" (-2).toFixed(0);",
|
||||
" 2;",
|
||||
" 2..toFixed(0);",
|
||||
" .2;",
|
||||
" .2.toFixed(0);",
|
||||
" 234e18;",
|
||||
" 234e18.toFixed(0);",
|
||||
" 2e-8;",
|
||||
" 2e-8.toFixed(0);",
|
||||
" 0xde0b6b3a7640080;",
|
||||
" (0xde0b6b3a7640080).toFixed(0);",
|
||||
" -0xde0b6b3a7640080;",
|
||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
||||
"}",
|
||||
"(function() {",
|
||||
" console.log(-2);",
|
||||
" console.log((-2).toFixed(0));",
|
||||
" console.log(2);",
|
||||
" console.log(2..toFixed(0));",
|
||||
" console.log(.2);",
|
||||
" console.log(.2.toFixed(0));",
|
||||
" console.log(234e18);",
|
||||
" console.log(234e18.toFixed(0));",
|
||||
" console.log(2e-8);",
|
||||
" console.log(2e-8.toFixed(0));",
|
||||
" console.log(0xde0b6b3a7640080);",
|
||||
" console.log(0xde0b6b3a7640080.toFixed(0));",
|
||||
" console.log(-0xde0b6b3a7640080);",
|
||||
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||
"})();",
|
||||
]
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
parentheses_for_prototype_functions_galio: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
galio: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
console.log((-2));
|
||||
console.log((-2).toFixed(0));
|
||||
|
||||
console.log((2));
|
||||
console.log((2).toFixed(0));
|
||||
|
||||
console.log((0.2));
|
||||
console.log((0.2).toFixed(0));
|
||||
|
||||
console.log((2.34e20));
|
||||
console.log((2.34e20).toFixed(0));
|
||||
|
||||
console.log((0.00000002));
|
||||
console.log((0.00000002).toFixed(0));
|
||||
|
||||
console.log((1000000000000000128));
|
||||
console.log((1000000000000000128).toFixed(0));
|
||||
|
||||
console.log((-1000000000000000128));
|
||||
console.log((-1000000000000000128).toFixed(0));
|
||||
})();
|
||||
}
|
||||
expect_exact: [
|
||||
"(function() {",
|
||||
" console.log(-2);",
|
||||
" console.log((-2).toFixed(0));",
|
||||
" console.log(2);",
|
||||
" console.log(2..toFixed(0));",
|
||||
" console.log(.2);",
|
||||
" console.log(.2.toFixed(0));",
|
||||
" console.log(234e18);",
|
||||
" console.log(234e18.toFixed(0));",
|
||||
" console.log(2e-8);",
|
||||
" console.log(2e-8.toFixed(0));",
|
||||
" console.log(0xde0b6b3a7640080);",
|
||||
" console.log((0xde0b6b3a7640080).toFixed(0));",
|
||||
" console.log(-0xde0b6b3a7640080);",
|
||||
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||
"})();",
|
||||
]
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
comparisons: {
|
||||
@@ -91,7 +142,7 @@ evaluate_1: {
|
||||
expect: {
|
||||
console.log(
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
2 * +x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -130,7 +181,7 @@ evaluate_1_unsafe_math: {
|
||||
expect: {
|
||||
console.log(
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
2 * +x,
|
||||
+x + 3,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
@@ -148,45 +199,52 @@ evaluate_1_unsafe_math: {
|
||||
evaluate_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 3,
|
||||
1 + (x*y + 2) + 3,
|
||||
1 + (2 + x + 3),
|
||||
1 + (2 + ~x + 3),
|
||||
-y + (2 + ~x + 3),
|
||||
1 & (2 & x & 3),
|
||||
1 + (2 + (x |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 3,
|
||||
1 + (x*y + 2) + 3,
|
||||
1 + (2 + x + 3),
|
||||
1 + (2 + ~x + 3),
|
||||
-y + (2 + ~x + 3),
|
||||
1 & (2 & x & 3),
|
||||
1 + (2 + (x |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
1 + x-- + 2 + 3,
|
||||
x*y + 2 + 1 + 3,
|
||||
1 + (2 + x + 3),
|
||||
2 + ~x + 3 + 1,
|
||||
2 + ~x + 3 - y,
|
||||
0 & x,
|
||||
2 + (x |= 0) + 3 + 1,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + "12",
|
||||
2 * x,
|
||||
+x + 1 + 2,
|
||||
1 + x + "23",
|
||||
3 | x,
|
||||
1 + x-- + 2 + 3,
|
||||
x*y + 2 + 1 + 3,
|
||||
2 + x + 3 + 1,
|
||||
2 + ~x + 3 + 1,
|
||||
2 + ~x + 3,
|
||||
0 & x,
|
||||
2 + (x |= 0) + 3 + 1,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"string 4212",
|
||||
@@ -207,45 +265,52 @@ evaluate_2: {
|
||||
evaluate_2_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 3,
|
||||
1 + (x*y + 2) + 3,
|
||||
1 + (2 + x + 3),
|
||||
1 + (2 + ~x + 3),
|
||||
-y + (2 + ~x + 3),
|
||||
1 & (2 & x & 3),
|
||||
1 + (2 + (x |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
x * 1 * 2,
|
||||
+x + 1 + 2,
|
||||
1 + x + 2 + 3,
|
||||
1 | x | 2 | 3,
|
||||
1 + x-- + 2 + 3,
|
||||
1 + (x*y + 2) + 3,
|
||||
1 + (2 + x + 3),
|
||||
1 + (2 + ~x + 3),
|
||||
-y + (2 + ~x + 3),
|
||||
1 & (2 & x & 3),
|
||||
1 + (2 + (x |= 0) + 3),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y = null;
|
||||
[
|
||||
x + 1 + 2,
|
||||
2 * x,
|
||||
+x + 3,
|
||||
1 + x + 2 + 3,
|
||||
3 | x,
|
||||
6 + x--,
|
||||
x*y + 6,
|
||||
1 + (2 + x + 3),
|
||||
6 + ~x,
|
||||
5 + ~x - y,
|
||||
0 & x,
|
||||
6 + (x |= 0),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var x = "" + num, y = null;
|
||||
[
|
||||
x + "12",
|
||||
2 * x,
|
||||
+x + 3,
|
||||
1 + x + "23",
|
||||
3 | x,
|
||||
6 + x--,
|
||||
x*y + 6,
|
||||
6 + x,
|
||||
6 + ~x,
|
||||
5 + ~x,
|
||||
0 & x,
|
||||
6 + (x |= 0),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"string 4212",
|
||||
@@ -310,45 +375,52 @@ evaluate_4: {
|
||||
evaluate_5: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
a - 2 + 3,
|
||||
a - 2 - 3,
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
2 - a + 3,
|
||||
2 - a - 3,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
a - 2 + 3,
|
||||
a - 2 - 3,
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
2 - a + 3,
|
||||
2 - a - 3,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 6",
|
||||
@@ -369,45 +441,52 @@ evaluate_5: {
|
||||
evaluate_5_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 2 + 3,
|
||||
+a + 2 - 3,
|
||||
+a - 2 + 3,
|
||||
+a - 2 - 3,
|
||||
2 + +a + 3,
|
||||
2 + +a - 3,
|
||||
2 - +a + 3,
|
||||
2 - +a - 3,
|
||||
2 + 3 + +a,
|
||||
2 + 3 - +a,
|
||||
2 - 3 + +a,
|
||||
2 - 3 - +a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect: {
|
||||
var a = "1";
|
||||
[
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
a - -1,
|
||||
a - 5,
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
5 - a,
|
||||
-1 - a,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num) {
|
||||
var a = "" + num;
|
||||
[
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
a - -1,
|
||||
a - 5,
|
||||
+a + 5,
|
||||
+a + -1,
|
||||
5 - a,
|
||||
-1 - a,
|
||||
+a + 5,
|
||||
5 - a,
|
||||
+a - 1,
|
||||
-1 - a,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 6",
|
||||
@@ -546,37 +625,44 @@ evaluate_6_unsafe_math: {
|
||||
evaluate_7: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: false,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
+x - 2 + (3 + !y),
|
||||
+x - 2 + (3 - !y),
|
||||
+x - 2 - (3 + !y),
|
||||
+x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num, y) {
|
||||
var x = "" + num;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
+x - 2 + (3 + !y),
|
||||
+x - 2 + (3 - !y),
|
||||
+x - 2 - (3 + !y),
|
||||
+x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
x - 2 + (3 + !y),
|
||||
x - 2 + (3 - !y),
|
||||
x - 2 - (3 + !y),
|
||||
x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num, y) {
|
||||
var x = "" + num;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
x - 2 + (3 + !y),
|
||||
x - 2 + (3 - !y),
|
||||
x - 2 - (3 + !y),
|
||||
x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 48",
|
||||
@@ -593,37 +679,44 @@ evaluate_7: {
|
||||
evaluate_7_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var x = "42", y;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
+x - 2 + (3 + !y),
|
||||
+x - 2 + (3 - !y),
|
||||
+x - 2 - (3 + !y),
|
||||
+x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num, y) {
|
||||
var x = "" + num;
|
||||
[
|
||||
+x + 2 + (3 + !y),
|
||||
+x + 2 + (3 - !y),
|
||||
+x + 2 - (3 + !y),
|
||||
+x + 2 - (3 - !y),
|
||||
+x - 2 + (3 + !y),
|
||||
+x - 2 + (3 - !y),
|
||||
+x - 2 - (3 + !y),
|
||||
+x - 2 - (3 - !y),
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect: {
|
||||
var x = "42", y;
|
||||
[
|
||||
+x + 5 + !y,
|
||||
+x + 5 - !y,
|
||||
+x + -1 - !y,
|
||||
+x + -1 + !y,
|
||||
x - -1 + !y,
|
||||
x - -1 - !y,
|
||||
x - 5 - !y,
|
||||
x - 5 + !y,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
function f(num, y) {
|
||||
var x = "" + num;
|
||||
[
|
||||
+x + 5 + !y,
|
||||
+x + 5 - !y,
|
||||
+x + -1 - !y,
|
||||
+x + -1 + !y,
|
||||
x - -1 + !y,
|
||||
x - -1 - !y,
|
||||
x - 5 - !y,
|
||||
x - 5 + !y,
|
||||
].forEach(function(n) {
|
||||
console.log(typeof n, n);
|
||||
});
|
||||
}
|
||||
f(42);
|
||||
}
|
||||
expect_stdout: [
|
||||
"number 48",
|
||||
@@ -637,6 +730,22 @@ evaluate_7_unsafe_math: {
|
||||
]
|
||||
}
|
||||
|
||||
evaluate_8_unsafe_math: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe_math: true,
|
||||
}
|
||||
input: {
|
||||
var a = [ "42" ];
|
||||
console.log(a * (1 / 7));
|
||||
}
|
||||
expect: {
|
||||
var a = [ "42" ];
|
||||
console.log(+a / 7);
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
NaN_redefined: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -1251,3 +1360,29 @@ issue_3695: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_4137: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(+(A = []) * (A[0] = 1));
|
||||
}
|
||||
expect: {
|
||||
console.log(+(A = []) * (A[0] = 1));
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4142: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log("" + +(0 === console));
|
||||
}
|
||||
expect: {
|
||||
console.log("" + +(0 === console));
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ duplicate_key_strict: {
|
||||
"use strict";
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
a: 3,
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
@@ -221,3 +221,195 @@ numeric_literal: {
|
||||
"8 7 8",
|
||||
]
|
||||
}
|
||||
|
||||
evaluate_computed_key: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
["foo" + "bar"]: "PASS",
|
||||
}.foobar);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
foobar: "PASS",
|
||||
}.foobar);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
keep_computed_key: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
[console.log("PASS")]: 42,
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
[0]: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
[0]: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get [0]() {
|
||||
return "FAIL";
|
||||
},
|
||||
0: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get [0]() {
|
||||
return "FAIL";
|
||||
},
|
||||
0: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
["foo"]: "bar",
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
foo: "bar",
|
||||
get [42]() {
|
||||
return "FAIL";
|
||||
},
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
["foo"]: "bar",
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
foo: "bar",
|
||||
[42]: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4269_5: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
[console]: "bar",
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
[console]: "bar",
|
||||
42: "PASS",
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4380: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
objects: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL 1";
|
||||
},
|
||||
0: "FAIL 2",
|
||||
[0]: "PASS",
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
get 0() {
|
||||
return "FAIL 1";
|
||||
},
|
||||
[0]: ("FAIL 2", "PASS"),
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -1123,11 +1123,7 @@ new_this: {
|
||||
}
|
||||
}.f(42);
|
||||
}
|
||||
expect: {
|
||||
new function(a) {
|
||||
this.a = a;
|
||||
}(42);
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2513: {
|
||||
|
||||
@@ -848,9 +848,8 @@ collapse_vars_1_true: {
|
||||
}
|
||||
expect: {
|
||||
function f(a, b) {
|
||||
for (;;) {
|
||||
for (;;)
|
||||
if (a.g() || b.p) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ modified: {
|
||||
expect: {
|
||||
function f0() {
|
||||
var b = 2;
|
||||
b++;
|
||||
+b;
|
||||
console.log(2);
|
||||
console.log(4);
|
||||
}
|
||||
@@ -1624,7 +1624,7 @@ defun_label: {
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
double_reference: {
|
||||
double_reference_1: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
@@ -1638,6 +1638,32 @@ double_reference: {
|
||||
g();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
var g = function g() {
|
||||
g();
|
||||
};
|
||||
g();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double_reference_2: {
|
||||
options = {
|
||||
functions: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var g = function g() {
|
||||
g();
|
||||
};
|
||||
g();
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
(function g() {
|
||||
@@ -1647,6 +1673,60 @@ double_reference: {
|
||||
}
|
||||
}
|
||||
|
||||
double_reference_3: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var x = function f() {
|
||||
return f;
|
||||
};
|
||||
function g() {
|
||||
return x();
|
||||
}
|
||||
console.log(g() === g());
|
||||
}
|
||||
expect: {
|
||||
var x = function f() {
|
||||
return f;
|
||||
};
|
||||
function g() {
|
||||
return x();
|
||||
}
|
||||
console.log(g() === g());
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
double_reference_4: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
functions: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var x = function f() {
|
||||
return f;
|
||||
};
|
||||
function g() {
|
||||
return x();
|
||||
}
|
||||
console.log(g() === g());
|
||||
}
|
||||
expect: {
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
iife_arguments_1: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
@@ -1686,8 +1766,35 @@ iife_arguments_2: {
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log(function f() {
|
||||
var x = function f() {
|
||||
return f;
|
||||
};
|
||||
console.log(x() === arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_arguments_3: {
|
||||
options = {
|
||||
functions: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var x = function f() {
|
||||
return f;
|
||||
};
|
||||
console.log(x() === arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log(function x() {
|
||||
return x;
|
||||
}() === arguments[0]);
|
||||
})();
|
||||
}
|
||||
@@ -1892,7 +1999,7 @@ issue_1606: {
|
||||
var a, b;
|
||||
function g(){};
|
||||
b = 2;
|
||||
x(b);
|
||||
x(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2069,6 +2176,7 @@ issue_1670_6: {
|
||||
keep_fargs: false,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
@@ -2086,10 +2194,9 @@ issue_1670_6: {
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
a = 1;
|
||||
console.log(a);
|
||||
})(1);
|
||||
(function() {
|
||||
console.log(1);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
@@ -2308,7 +2415,7 @@ redefine_farg_2: {
|
||||
console.log(typeof [], "number",function(a, b) {
|
||||
a = b;
|
||||
return typeof a;
|
||||
}([]));
|
||||
}());
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
@@ -5267,11 +5374,11 @@ defun_catch_4: {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
function a() {}
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: "<=4"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
defun_catch_5: {
|
||||
@@ -5293,10 +5400,10 @@ defun_catch_5: {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
console.log(a);
|
||||
function a() {}
|
||||
}
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: "<=4"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
defun_catch_6: {
|
||||
@@ -5483,7 +5590,7 @@ lvalues_def_1: {
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
var a = b++, b = NaN;
|
||||
var a = +b, b = NaN;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "1 NaN"
|
||||
@@ -7428,3 +7535,69 @@ global_assign: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4188_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
try {
|
||||
while (A)
|
||||
var a = function() {}, b = a;
|
||||
} catch (a) {
|
||||
console.log(function() {
|
||||
return typeof a;
|
||||
}(), typeof b);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
try {
|
||||
while (A)
|
||||
var a = function() {}, b = a;
|
||||
} catch (a) {
|
||||
console.log(function() {
|
||||
return typeof a;
|
||||
}(), typeof b);
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect_stdout: "object undefined"
|
||||
}
|
||||
|
||||
issue_4188_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
console.log(function() {
|
||||
return typeof a;
|
||||
}(), typeof b);
|
||||
}
|
||||
while (!console)
|
||||
var a = function() {}, b = a;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
try {
|
||||
throw 42;
|
||||
} catch (a) {
|
||||
console.log(function() {
|
||||
return typeof a;
|
||||
}(), typeof b);
|
||||
}
|
||||
while (!console)
|
||||
var a = function() {}, b = a;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "number undefined"
|
||||
}
|
||||
|
||||
@@ -877,7 +877,7 @@ for_init_var: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
forin: {
|
||||
forin_1: {
|
||||
options = {
|
||||
sequences: true,
|
||||
}
|
||||
@@ -895,6 +895,49 @@ forin: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
forin_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
p: 1,
|
||||
q: 2,
|
||||
};
|
||||
var k = "k";
|
||||
for ((console.log("exp"), o)[function() {
|
||||
console.log("prop");
|
||||
return k;
|
||||
}()] in function() {
|
||||
console.log("obj");
|
||||
return o;
|
||||
}())
|
||||
console.log(o.k, o[o.k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: 1,
|
||||
q: 2,
|
||||
};
|
||||
for ((console.log("exp"), o)[console.log("prop"), "k"] in console.log("obj"), o)
|
||||
console.log(o.k, o[o.k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"obj",
|
||||
"exp",
|
||||
"prop",
|
||||
"p 1",
|
||||
"exp",
|
||||
"prop",
|
||||
"q 2",
|
||||
]
|
||||
}
|
||||
|
||||
call: {
|
||||
options = {
|
||||
sequences: true,
|
||||
@@ -1112,3 +1155,25 @@ issue_3703: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4079: {
|
||||
options = {
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
typeof (0, A);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
A;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -245,6 +245,31 @@ unsafe_builtin_2: {
|
||||
expect_stdout: "object PASS PASS"
|
||||
}
|
||||
|
||||
unsafe_builtin_3: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = {};
|
||||
if (42 < Math.random())
|
||||
o.p = "FAIL";
|
||||
else
|
||||
o.p = "PASS";
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {};
|
||||
o.p = 42 < Math.random() ? "FAIL" : "PASS";
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: "p PASS"
|
||||
}
|
||||
|
||||
unsafe_string_replace: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
@@ -391,3 +416,93 @@ issue_4008: {
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
trim_new: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
new function(a) {
|
||||
console.log(a);
|
||||
}("PASS");
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
console.log(a);
|
||||
})("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4325: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
passes: 2,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
(function(b, c) {
|
||||
try {
|
||||
c.p = 0;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
return b;
|
||||
}
|
||||
c;
|
||||
})(f++);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function() {
|
||||
try {
|
||||
(void 0).p = 0;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
return;
|
||||
}
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_4366_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
p: 42,
|
||||
get p() {},
|
||||
q: console.log("PASS"),
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4366_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
set p(v) {},
|
||||
q: console.log("PASS"),
|
||||
p: 42,
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
806
test/compress/spread.js
Normal file
806
test/compress/spread.js
Normal file
@@ -0,0 +1,806 @@
|
||||
collapse_vars_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a;
|
||||
[ ...a = "PASS", "PASS"].slice();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a;
|
||||
[ ...a = "PASS", "PASS"].slice();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
[ ...42, "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
a = "PASS";
|
||||
[ ...42, "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
[ ...(a = "PASS", 42), "PASS"].slice();
|
||||
} catch (e) {
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
collapse_vars_4: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
dont_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
do_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return a;
|
||||
}(...[ "PASS", "FAIL" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(("FAIL", "PASS"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_empty_call_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
(function() {})(...null);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
[ ...null ];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
drop_empty_call_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
(function() {})(...[ console.log("PASS") ]);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
convert_hole: {
|
||||
options = {
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log(...[ "PASS", , 42 ]);
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS", void 0, 42);
|
||||
}
|
||||
expect_stdout: "PASS undefined 42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
keep_property_access: {
|
||||
options = {
|
||||
properties: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
return [ ..."foo" ][0];
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
return [ ..."foo" ][0];
|
||||
}());
|
||||
}
|
||||
expect_stdout: "f"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
keep_fargs: {
|
||||
options = {
|
||||
keep_fargs: "strict",
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = [ "PASS" ];
|
||||
(function(b, c) {
|
||||
console.log(c);
|
||||
})(console, ...a);
|
||||
}
|
||||
expect: {
|
||||
var a = [ "PASS" ];
|
||||
(function(b, c) {
|
||||
console.log(c);
|
||||
})(console, ...a);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_vars_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
reduce_vars_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(b, c) {
|
||||
return c ? "PASS" : "FAIL";
|
||||
}(..."foo"));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
convert_setter: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
...{
|
||||
set PASS(v) {},
|
||||
},
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
PASS: void 0,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: "PASS undefined"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_getter_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
...{
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
},
|
||||
get q() {
|
||||
console.log("FAIL");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
...{
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_getter_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
...(console.log("foo"), {
|
||||
get p() {
|
||||
console.log("bar");
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
...(console.log("foo"), {
|
||||
get p() {
|
||||
console.log("bar");
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"bar",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_getter_3: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
...function() {
|
||||
return {
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
};
|
||||
}(),
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
...function() {
|
||||
return {
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
};
|
||||
}(),
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_getter_4: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
};
|
||||
({
|
||||
q: o,
|
||||
...o,
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
};
|
||||
({
|
||||
...o,
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
keep_accessor: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
...{
|
||||
get p() {
|
||||
console.log("GET");
|
||||
return this.r;
|
||||
},
|
||||
set q(v) {
|
||||
console.log("SET", v);
|
||||
},
|
||||
r: 42,
|
||||
},
|
||||
r: null,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
...{
|
||||
get p() {
|
||||
console.log("GET");
|
||||
return this.r;
|
||||
},
|
||||
set q(v) {
|
||||
console.log("SET", v);
|
||||
},
|
||||
r: 42,
|
||||
},
|
||||
r: null,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"GET",
|
||||
"p 42",
|
||||
"q undefined",
|
||||
"r null",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_key_order_1: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
...{},
|
||||
a: 1,
|
||||
b: 2,
|
||||
a: 3,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: (1, 3),
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"a 3",
|
||||
"b 2",
|
||||
]
|
||||
node_version: ">=8 <=10"
|
||||
}
|
||||
|
||||
object_key_order_2: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
...{},
|
||||
b: 2,
|
||||
a: 3,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: (1, 3),
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"a 3",
|
||||
"b 2",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_key_order_3: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
...{},
|
||||
a: 3,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: (1, 3),
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"a 3",
|
||||
"b 2",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_key_order_4: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
a: 3,
|
||||
...{},
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
a: (1, 3),
|
||||
b: 2,
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"a 3",
|
||||
"b 2",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_spread_array: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
...[ "foo", "bar" ],
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
...[ "foo", "bar" ],
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 foo",
|
||||
"1 bar",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
object_spread_string: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
..."foo",
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
..."foo",
|
||||
};
|
||||
for (var k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 f",
|
||||
"1 o",
|
||||
"2 o",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
unused_var_side_effects: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f(a) {
|
||||
var b = {
|
||||
...a,
|
||||
};
|
||||
})({
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
({
|
||||
...a,
|
||||
});
|
||||
})({
|
||||
get p() {
|
||||
console.log("PASS");
|
||||
},
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4329: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
...{
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
...{
|
||||
0: "PASS",
|
||||
},
|
||||
},
|
||||
}[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
...{
|
||||
get 0() {
|
||||
return "FAIL";
|
||||
},
|
||||
[0]: "PASS",
|
||||
},
|
||||
}[0]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4331: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS", b;
|
||||
console,
|
||||
b = a;
|
||||
(function() {
|
||||
a++;
|
||||
})(...a);
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = "PASS", b;
|
||||
console;
|
||||
(function() {
|
||||
a++;
|
||||
})(...b = a);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4342: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
new function() {}(...42);
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
[ ...42 ];
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4345: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
...{
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
...{},
|
||||
42: "PASS",
|
||||
},
|
||||
}[42]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
...{
|
||||
get 42() {
|
||||
return "FAIL";
|
||||
},
|
||||
[42]: "PASS",
|
||||
},
|
||||
}[42]);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4361: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var a = console.log("foo");
|
||||
console;
|
||||
var b = {
|
||||
...a,
|
||||
};
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var a = console.log("foo");
|
||||
console;
|
||||
({
|
||||
...a,
|
||||
});
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"undefined",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
issue_4363: {
|
||||
options = {
|
||||
objects: true,
|
||||
spread: true,
|
||||
}
|
||||
input: {
|
||||
({
|
||||
...{
|
||||
set [console.log("PASS")](v) {},
|
||||
},
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
({
|
||||
[console.log("PASS")]: void 0,
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=8"
|
||||
}
|
||||
@@ -1,3 +1,37 @@
|
||||
ascii_only_false: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"\x000\x001\x007\x008\x00",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||
);
|
||||
}
|
||||
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f","\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\');'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
ascii_only_true: {
|
||||
options = {}
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"\x000\x001\x007\x008\x00",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"
|
||||
);
|
||||
}
|
||||
expect_exact: 'console.log("\\x000\\x001\\x007\\x008\\0","\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f","\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f",\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\');'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unicode_parse_variables: {
|
||||
options = {}
|
||||
input: {
|
||||
@@ -141,3 +175,35 @@ issue_2569: {
|
||||
}
|
||||
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
|
||||
}
|
||||
|
||||
surrogate_pair: {
|
||||
beautify = {
|
||||
ascii_only: false,
|
||||
}
|
||||
input: {
|
||||
var \u{2f800} = {
|
||||
\u{2f801}: "\u{100000}",
|
||||
};
|
||||
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||
}
|
||||
expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);'
|
||||
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
surrogate_pair_ascii: {
|
||||
beautify = {
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
var \u{2f800} = {
|
||||
\u{2f801}: "\u{100000}",
|
||||
};
|
||||
\u{2f800}.\u{2f802} = "\u{100001}";
|
||||
console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]);
|
||||
}
|
||||
expect_exact: 'var \\u{2f800}={"\\ud87e\\udc01":"\\udbc0\\udc00"};\\u{2f800}.\\u{2f802}="\\udbc0\\udc01";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\ud87e\\udc02"]);'
|
||||
expect_stdout: "object \udbc0\udc00 \udbc0\udc01"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
411
test/compress/varify.js
Normal file
411
test/compress/varify.js
Normal file
@@ -0,0 +1,411 @@
|
||||
reduce_merge_const: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const a = console;
|
||||
console.log(typeof a);
|
||||
var b = typeof a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = console;
|
||||
console.log(typeof b);
|
||||
b = typeof b;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
}
|
||||
|
||||
reduce_merge_let: {
|
||||
options = {
|
||||
merge_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = console;
|
||||
console.log(typeof a);
|
||||
var b = typeof a;
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var b = console;
|
||||
console.log(typeof b);
|
||||
b = typeof b;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
reduce_block_const: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
}
|
||||
|
||||
reduce_block_let: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
{
|
||||
let a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var a = typeof console;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "object"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
hoist_props_const: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
{
|
||||
const o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var o_p = "PASS";
|
||||
console.log(o_p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
hoist_props_let: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
{
|
||||
let o = {
|
||||
p: "PASS",
|
||||
};
|
||||
console.log(o.p);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o_p = "PASS";
|
||||
console.log(o_p);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
scope_adjustment_const: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(function f() {
|
||||
if (k) {
|
||||
const a = 0;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
for (var k in [ 42 ])
|
||||
console.log(void (k && 0));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
scope_adjustment_let: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
for (var k in [ 42 ])
|
||||
console.log(function f() {
|
||||
if (k) {
|
||||
let a = 0;
|
||||
}
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
for (var k in [ 42 ])
|
||||
console.log(void (k && 0));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_4191_const: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const a = function() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect: {
|
||||
function a() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
}
|
||||
|
||||
issue_4191_let: {
|
||||
options = {
|
||||
functions: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = function() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function a() {};
|
||||
console.log(typeof a, a());
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
forin_const_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const o = {
|
||||
foo: 42,
|
||||
bar: "PASS",
|
||||
};
|
||||
for (const k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
foo: 42,
|
||||
bar: "PASS",
|
||||
};
|
||||
for (const k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
forin_const_2: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const o = {
|
||||
p: 42,
|
||||
q: "PASS",
|
||||
};
|
||||
for (const [ k ] in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: 42,
|
||||
q: "PASS",
|
||||
}, k;
|
||||
for ([ k ] in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"p 42",
|
||||
"q PASS",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
forin_let_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let o = {
|
||||
foo: 42,
|
||||
bar: "PASS",
|
||||
};
|
||||
for (let k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var o = {
|
||||
foo: 42,
|
||||
bar: "PASS",
|
||||
}, k;
|
||||
for (k in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo 42",
|
||||
"bar PASS",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
forin_let_2: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
let o = {
|
||||
p: 42,
|
||||
q: "PASS",
|
||||
};
|
||||
for (let [ k ] in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
p: 42,
|
||||
q: "PASS",
|
||||
}, k;
|
||||
for ([ k ] in o)
|
||||
console.log(k, o[k]);
|
||||
}
|
||||
expect_stdout: [
|
||||
"p 42",
|
||||
"q PASS",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_4290_1_const: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
const a = 0;
|
||||
var a;
|
||||
}
|
||||
expect: {
|
||||
const a = 0;
|
||||
var a;
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_4290_1_let: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
let a = 0;
|
||||
var a;
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
let a = 0;
|
||||
var a;
|
||||
}
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
drop_forin_let: {
|
||||
options = {
|
||||
loops: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
varify: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
for (let a in console.log("PASS"));
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
new function(){console.log(3)};
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||
console.log(3);
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSJ9
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
new function(){console.log(3)};
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||
console.log(3);
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSJ9
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
var o = this;
|
||||
|
||||
for (var k in o) L17060: {
|
||||
a++;
|
||||
UNUSED: {
|
||||
console.log(0 - .1 - .1 - .1);
|
||||
}
|
||||
|
||||
var a;
|
||||
|
||||
console.log(k);
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// (beautified)
|
||||
var o = this;
|
||||
|
||||
for (var k in o) {}
|
||||
|
||||
var a;
|
||||
|
||||
console.log(k);
|
||||
// output: a
|
||||
console.log(0 - 1 - .1 - .1);
|
||||
// output: -1.2000000000000002
|
||||
//
|
||||
// minify: k
|
||||
// minify: -1.2
|
||||
//
|
||||
// options: {
|
||||
// "compress": {
|
||||
// "unsafe_math": true
|
||||
// },
|
||||
// "mangle": false
|
||||
// }
|
||||
@@ -60,7 +60,7 @@ if (typeof phantom == "undefined") {
|
||||
var port = server.address().port;
|
||||
if (debug) {
|
||||
console.log("http://localhost:" + port + "/");
|
||||
} else {
|
||||
} else (function install() {
|
||||
child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
|
||||
"install",
|
||||
"phantomjs-prebuilt@2.1.14",
|
||||
@@ -71,7 +71,10 @@ if (typeof phantom == "undefined") {
|
||||
], {
|
||||
stdio: [ "ignore", 1, 2 ]
|
||||
}).on("exit", function(code) {
|
||||
if (code) throw new Error("npm install failed!");
|
||||
if (code) {
|
||||
console.log("npm install failed with code", code);
|
||||
return install();
|
||||
}
|
||||
var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
|
||||
program.stdout.pipe(process.stdout);
|
||||
program.stderr.pipe(process.stderr);
|
||||
@@ -82,7 +85,7 @@ if (typeof phantom == "undefined") {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
||||
server.timeout = 0;
|
||||
} else {
|
||||
|
||||
65
test/mocha/async.js
Normal file
65
test/mocha/async.js
Normal file
@@ -0,0 +1,65 @@
|
||||
var assert = require("assert");
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("async", function() {
|
||||
it("Should reject `await` as symbol name within async functions only", function() {
|
||||
[
|
||||
"function await() {}",
|
||||
"function(await) {}",
|
||||
"function() { await; }",
|
||||
"function() { await:{} }",
|
||||
"function() { var await; }",
|
||||
"function() { function await() {} }",
|
||||
"function() { try {} catch (await) {} }",
|
||||
].forEach(function(code) {
|
||||
var ast = UglifyJS.parse("(" + code + ")();");
|
||||
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||
assert.strictEqual(ast.body.length, 1);
|
||||
assert.strictEqual(ast.body[0].TYPE, "SimpleStatement");
|
||||
assert.strictEqual(ast.body[0].body.TYPE, "Call");
|
||||
assert.strictEqual(ast.body[0].body.expression.TYPE, "Function");
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse("(async " + code + ")();");
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
it("Should reject `await` expression outside of async functions", function() {
|
||||
[
|
||||
"await 42;",
|
||||
"function f() { await 42; }",
|
||||
"async function f() { function g() { await 42; } }",
|
||||
].forEach(function(code) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(code);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
it("Should reject `await` expression directly on computed key of function argument", function() {
|
||||
[
|
||||
"function f({ [await 42]: a }) {}",
|
||||
"async function f({ [await 42]: a }) {}",
|
||||
].forEach(function(code) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(code);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
it("Should accept `await` expression nested within computed key of function argument", function() {
|
||||
[
|
||||
"function f({ [async function() { await 42; }()]: a }) {}",
|
||||
"async function f({ [async function() { await 42; }()]: a }) {}",
|
||||
].forEach(function(code) {
|
||||
var ast = UglifyJS.parse(code);
|
||||
assert.strictEqual(ast.TYPE, "Toplevel");
|
||||
assert.strictEqual(ast.body.length, 1);
|
||||
assert.strictEqual(ast.body[0].argnames.length, 1);
|
||||
assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -28,4 +28,65 @@ describe("Number literals", function() {
|
||||
assert.throws(test(inputs[i]), error, inputs[i]);
|
||||
}
|
||||
});
|
||||
it("Should parse binary, hexadecimal, octal and underscore correctly", function() {
|
||||
[
|
||||
"42",
|
||||
"4_2",
|
||||
"052",
|
||||
"0o52",
|
||||
"0O52",
|
||||
"0o5_2",
|
||||
"0x2a",
|
||||
"0X2A",
|
||||
"0x2_a",
|
||||
"0b101010",
|
||||
"0B101010",
|
||||
"0b101_010",
|
||||
"0.0000000042e+10",
|
||||
"0.0000000042E+10",
|
||||
"0.0_000000042e+10",
|
||||
"0.0000000042e+1_0",
|
||||
"0.000_000_004_2e+1_0",
|
||||
"0.000_000_004_2e+1_0-0B101_010+0x2_A-0o5_2+4_2",
|
||||
].forEach(function(code) {
|
||||
var result = UglifyJS.minify(code, {
|
||||
compress: {
|
||||
expression: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, "42;");
|
||||
});
|
||||
});
|
||||
it("Should reject invalid use of underscore", function() {
|
||||
[
|
||||
"_42",
|
||||
"_+42",
|
||||
"+_42",
|
||||
].forEach(function(code) {
|
||||
var node = UglifyJS.parse(code, {
|
||||
expression: true,
|
||||
});
|
||||
assert.ok(!node.is_constant(), code);
|
||||
assert.ok(!(node instanceof UglifyJS.AST_Statement), code);
|
||||
});
|
||||
[
|
||||
"42_",
|
||||
"4__2",
|
||||
"0_52",
|
||||
"05_2",
|
||||
"0_o52",
|
||||
"0o_52",
|
||||
"0.0000000042_e10",
|
||||
"0.0000000042e_10",
|
||||
"0.0000000042e_+10",
|
||||
"0.0000000042e+_10",
|
||||
].forEach(function(code) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(code);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,6 +24,9 @@ describe("test/reduce.js", function() {
|
||||
});
|
||||
it("Should eliminate unreferenced labels", function() {
|
||||
var result = reduce_test(read("test/input/reduce/label.js"), {
|
||||
compress: {
|
||||
unsafe_math: true,
|
||||
},
|
||||
mangle: false,
|
||||
}, {
|
||||
verbose: false,
|
||||
|
||||
@@ -1,64 +1,58 @@
|
||||
var assert = require("assert");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("String literals", function() {
|
||||
it("Should throw syntax error if a string literal contains a newline", function() {
|
||||
var inputs = [
|
||||
[
|
||||
"'\n'",
|
||||
"'\r'",
|
||||
'"\r\n"',
|
||||
"'\u2028'",
|
||||
'"\u2029"'
|
||||
];
|
||||
|
||||
var test = function(input) {
|
||||
return function() {
|
||||
'"\u2029"',
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
var ast = UglifyJS.parse(input);
|
||||
};
|
||||
};
|
||||
|
||||
var error = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated string constant";
|
||||
};
|
||||
|
||||
for (var input in inputs) {
|
||||
assert.throws(test(inputs[input]), error);
|
||||
}
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated string constant";
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should handle line continuation correctly", function() {
|
||||
[
|
||||
'"\\\r"',
|
||||
'"\\\n"',
|
||||
'"\\\r\n"',
|
||||
].forEach(function(str) {
|
||||
var code = "console.log(" + str + ");";
|
||||
var result = UglifyJS.minify(code);
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(run_code(result.code), run_code(code));
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw syntax error if a string has a line continuation", function() {
|
||||
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
||||
assert.equal(output, 'var a="ab";');
|
||||
var ast = UglifyJS.parse('var a = "a\\\nb";');
|
||||
assert.equal(ast.print_to_string(), 'var a="ab";');
|
||||
});
|
||||
|
||||
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||
var inputs = [
|
||||
[
|
||||
'"use strict";\n"\\76";',
|
||||
'"use strict";\nvar foo = "\\76";',
|
||||
'"use strict";\n"\\1";',
|
||||
'"use strict";\n"\\07";',
|
||||
'"use strict";\n"\\011"'
|
||||
];
|
||||
|
||||
var test = function(input) {
|
||||
return function() {
|
||||
'"use strict";\n"\\011"',
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
var output = UglifyJS.parse(input);
|
||||
}
|
||||
};
|
||||
|
||||
var error = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||
}
|
||||
|
||||
for (var input in inputs) {
|
||||
assert.throws(test(inputs[input]), error);
|
||||
}
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||
var tests = [
|
||||
[
|
||||
[ ';"\\76";', ';">";' ],
|
||||
[ ';"\\0";', ';"\\0";' ],
|
||||
[ ';"\\08"', ';"\\x008";' ],
|
||||
@@ -66,19 +60,15 @@ describe("String literals", function() {
|
||||
[ ';"\\0008"', ';"\\x008";' ],
|
||||
[ ';"use\\\n strict";\n"\\07";', ';"use strict";"\07";' ],
|
||||
[ '"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";' ],
|
||||
];
|
||||
|
||||
for (var test in tests) {
|
||||
var output = UglifyJS.parse(tests[test][0]).print_to_string();
|
||||
assert.equal(output, tests[test][1]);
|
||||
}
|
||||
].forEach(function(test) {
|
||||
var ast = UglifyJS.parse(test[0]);
|
||||
assert.equal(ast.print_to_string(), test[1]);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should not throw error when digit is 8 or 9", function() {
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\08"').print_to_string(), '"use strict";;"\\x008";');
|
||||
assert.equal(UglifyJS.parse('"use strict";;"\\09"').print_to_string(), '"use strict";;"\\x009";');
|
||||
});
|
||||
|
||||
it("Should not unescape unpaired surrogates", function() {
|
||||
var code = [];
|
||||
for (var i = 0; i <= 0xF; i++) {
|
||||
@@ -115,4 +105,33 @@ describe("String literals", function() {
|
||||
assert.ok(code.length > ascii.code.length);
|
||||
assert.strictEqual(eval(code), eval(ascii.code));
|
||||
});
|
||||
it("Should reject invalid Unicode escape sequence", function() {
|
||||
[
|
||||
'var foo = "\\u-111"',
|
||||
'var bar = "\\u{-1}"',
|
||||
'var baz = "\\ugggg"',
|
||||
].forEach(function(test) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Invalid hex-character pattern in string";
|
||||
});
|
||||
});
|
||||
});
|
||||
it("Should reject invalid code points in Unicode escape sequence", function() {
|
||||
[
|
||||
// A bit over the valid range
|
||||
'"\\u{110000}"',
|
||||
// 32-bit overflow resulting in "a"
|
||||
'"\\u{100000061}"',
|
||||
].forEach(function(test) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(test);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& /^Invalid character code: /.test(e.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ describe("tokens", function() {
|
||||
it("Should give correct positions for accessors", function() {
|
||||
// location 0 1 2 3 4
|
||||
// 01234567890123456789012345678901234567890123456789
|
||||
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
|
||||
var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
|
||||
// test all AST_ObjectProperty tokens are set as expected
|
||||
var found = false;
|
||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
@@ -13,9 +13,9 @@ describe("tokens", function() {
|
||||
found = true;
|
||||
assert.equal(node.start.pos, 12);
|
||||
assert.equal(node.end.endpos, 46);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
||||
assert.equal(node.key.start.pos, 16);
|
||||
assert.equal(node.key.end.endpos, 22);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolRef);
|
||||
assert.equal(node.key.start.pos, 17);
|
||||
assert.equal(node.key.end.endpos, 21);
|
||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||
assert.equal(node.value.start.pos, 22);
|
||||
assert.equal(node.value.end.endpos, 46);
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("With", function() {
|
||||
var ast = UglifyJS.parse("with(e) {f(1, 2)}");
|
||||
ast.figure_out_scope();
|
||||
assert.equal(ast.uses_with, true);
|
||||
assert.equal(ast.body[0].expression.scope.uses_with, true);
|
||||
assert.equal(ast.body[0].body.body[0].body.expression.scope.uses_with, true);
|
||||
assert.equal(ast.body[0].expression.scope.resolve().uses_with, true);
|
||||
assert.equal(ast.body[0].body.body[0].body.expression.scope.resolve().uses_with, true);
|
||||
});
|
||||
});
|
||||
|
||||
171
test/reduce.js
171
test/reduce.js
@@ -18,9 +18,18 @@ var sandbox = require("./sandbox");
|
||||
|
||||
Error.stackTraceLimit = Infinity;
|
||||
module.exports = function reduce_test(testcase, minify_options, reduce_options) {
|
||||
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string();
|
||||
minify_options = minify_options || {};
|
||||
reduce_options = reduce_options || {};
|
||||
var print_options = {};
|
||||
[
|
||||
"ie8",
|
||||
"v8",
|
||||
"webkit",
|
||||
].forEach(function(name) {
|
||||
var value = minify_options[name] || minify_options.output && minify_options.output[name];
|
||||
if (value) print_options[name] = value;
|
||||
});
|
||||
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string(print_options);
|
||||
var max_iterations = reduce_options.max_iterations || 1000;
|
||||
var max_timeout = reduce_options.max_timeout || 10000;
|
||||
var warnings = [];
|
||||
@@ -95,6 +104,7 @@ 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;
|
||||
@@ -112,19 +122,20 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
// no structural AST changes before this point.
|
||||
if (node.start._permute >= REPLACEMENTS.length) return;
|
||||
|
||||
if (parent instanceof U.AST_Assign
|
||||
&& parent.left === node
|
||||
|| parent instanceof U.AST_Unary
|
||||
&& parent.expression === node
|
||||
&& ["++", "--", "delete"].indexOf(parent.operator) >= 0) {
|
||||
// ignore lvalues
|
||||
// ignore lvalues
|
||||
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||
if (parent instanceof U.AST_DestructuredArray) return;
|
||||
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
|
||||
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||
case "++":
|
||||
case "--":
|
||||
case "delete":
|
||||
return;
|
||||
}
|
||||
if ((parent instanceof U.AST_For || parent instanceof U.AST_ForIn)
|
||||
&& parent.init === node && node instanceof U.AST_Var) {
|
||||
// preserve for (var ...)
|
||||
return node;
|
||||
}
|
||||
// preserve for (var xxx; ...)
|
||||
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
|
||||
// preserve for (xxx in ...)
|
||||
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
||||
|
||||
// node specific permutations with no parent logic
|
||||
|
||||
@@ -133,7 +144,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
if (expr && !(expr instanceof U.AST_Hole)) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_Binary) {
|
||||
@@ -146,7 +157,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return permute < 2 ? expr : wrap_with_console_log(expr);
|
||||
}
|
||||
else if (node instanceof U.AST_BlockStatement) {
|
||||
if (in_list) {
|
||||
if (in_list && node.body.filter(function(node) {
|
||||
return node instanceof U.AST_Const;
|
||||
}).length == 0) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return List.splice(node.body);
|
||||
@@ -160,7 +173,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return expr;
|
||||
return expr instanceof U.AST_Spread ? expr.expression : expr;
|
||||
}
|
||||
if (node.expression instanceof U.AST_Function) {
|
||||
// hoist and return expressions from the IIFE function expression
|
||||
@@ -249,13 +262,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_ForIn) {
|
||||
var expr = [
|
||||
node.init,
|
||||
node.object,
|
||||
node.body,
|
||||
][ (node.start._permute * steps | 0) % 3 ];
|
||||
var expr;
|
||||
switch ((node.start._permute * steps | 0) % 3) {
|
||||
case 0:
|
||||
if (!(node.init instanceof U.AST_Definitions
|
||||
&& node.init.definitions[0].name instanceof U.AST_Destructured)) {
|
||||
expr = node.init;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
expr = node.object;
|
||||
break;
|
||||
case 2:
|
||||
if (!has_loopcontrol(node.body, node, parent)) expr = node.body;
|
||||
break;
|
||||
}
|
||||
node.start._permute += step;
|
||||
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return to_statement(expr);
|
||||
}
|
||||
@@ -367,9 +390,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
|
||||
if (in_list) {
|
||||
// special case to drop object properties and switch branches
|
||||
if (parent instanceof U.AST_Object
|
||||
|| parent instanceof U.AST_Switch && parent.expression != node) {
|
||||
// drop switch branches
|
||||
if (parent instanceof U.AST_Switch && parent.expression != node) {
|
||||
node.start._permute++;
|
||||
CHANGED = true;
|
||||
return List.skip;
|
||||
@@ -388,6 +410,15 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
// replace this node
|
||||
@@ -411,7 +442,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
start: {},
|
||||
});
|
||||
}
|
||||
else if (node instanceof U.AST_Var) {
|
||||
else if (node instanceof U.AST_Definitions) {
|
||||
// remove empty var statement
|
||||
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||
start: {},
|
||||
@@ -428,7 +459,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
if (node.TYPE == "Call" && node.expression.print_to_string() == "console.log") {
|
||||
return to_sequence(node.args);
|
||||
}
|
||||
if (node instanceof U.AST_Catch) {
|
||||
if (node instanceof U.AST_Catch && node.argname) {
|
||||
descend(node, this);
|
||||
node.body.unshift(new U.AST_SimpleStatement({
|
||||
body: wrap_with_console_log(new U.AST_SymbolRef(node.argname)),
|
||||
@@ -437,7 +468,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return node;
|
||||
}
|
||||
}));
|
||||
var code = testcase_ast.print_to_string();
|
||||
var code = testcase_ast.print_to_string(print_options);
|
||||
var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
|
||||
if (diff && !diff.timed_out && !diff.error) {
|
||||
testcase = code;
|
||||
@@ -452,6 +483,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
node.start = JSON.parse(JSON.stringify(node.start));
|
||||
node.start._permute = 0;
|
||||
}));
|
||||
var before_iterations = testcase;
|
||||
for (var c = 0; c < max_iterations; ++c) {
|
||||
if (verbose && pass == 1 && c % 25 == 0) {
|
||||
log("// reduce test pass " + pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||
@@ -460,7 +492,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
var code_ast = testcase_ast.clone(true).transform(tt);
|
||||
if (!CHANGED) break;
|
||||
try {
|
||||
var code = code_ast.print_to_string();
|
||||
var code = code_ast.print_to_string(print_options);
|
||||
} catch (ex) {
|
||||
// AST is not well formed.
|
||||
// no harm done - just log the error, ignore latest change and continue iterating.
|
||||
@@ -494,12 +526,33 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c == 0) break;
|
||||
if (before_iterations === testcase) break;
|
||||
if (verbose) {
|
||||
log("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||
}
|
||||
}
|
||||
testcase = try_beautify(testcase, minify_options, differs.unminified_result, result_cache, max_timeout);
|
||||
var beautified = U.minify(testcase, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: function() {
|
||||
var options = JSON.parse(JSON.stringify(print_options));
|
||||
options.beautify = true;
|
||||
options.braces = true;
|
||||
options.comments = true;
|
||||
return options;
|
||||
}(),
|
||||
});
|
||||
testcase = {
|
||||
code: testcase,
|
||||
};
|
||||
if (!beautified.error) {
|
||||
diff = test_for_diff(beautified.code, minify_options, result_cache, max_timeout);
|
||||
if (diff && !diff.timed_out && !diff.error) {
|
||||
testcase = beautified;
|
||||
testcase.code = "// (beautified)\n" + testcase.code;
|
||||
differs = diff;
|
||||
}
|
||||
}
|
||||
var lines = [ "" ];
|
||||
if (isNaN(max_timeout)) {
|
||||
lines.push("// minify error: " + to_comment(strip_color_codes(differs.minified_result.stack)));
|
||||
@@ -538,34 +591,6 @@ function trim_trailing_whitespace(value) {
|
||||
return ("" + value).replace(/\s+$/, "");
|
||||
}
|
||||
|
||||
function try_beautify(testcase, minify_options, expected, result_cache, timeout) {
|
||||
var result = U.minify(testcase, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
beautify: true,
|
||||
braces: true,
|
||||
comments: true,
|
||||
},
|
||||
});
|
||||
if (result.error) return {
|
||||
code: testcase,
|
||||
};
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
if (isNaN(timeout)) {
|
||||
if (!U.minify(result.code, minify_options).error) return {
|
||||
code: testcase,
|
||||
};
|
||||
} else {
|
||||
var actual = run_code(result.code, toplevel, result_cache, timeout);
|
||||
if (!sandbox.same_stdout(expected, actual)) return {
|
||||
code: testcase,
|
||||
};
|
||||
}
|
||||
result.code = "// (beautified)\n" + result.code;
|
||||
return result;
|
||||
}
|
||||
|
||||
function has_exit(fn) {
|
||||
var found = false;
|
||||
var tw = new U.TreeWalker(function(node) {
|
||||
@@ -600,11 +625,11 @@ function is_error(result) {
|
||||
}
|
||||
|
||||
function is_timed_out(result) {
|
||||
return is_error(result) && /timed out/.test(result);
|
||||
return is_error(result) && /timed out/.test(result.message);
|
||||
}
|
||||
|
||||
function is_statement(node) {
|
||||
return node instanceof U.AST_Statement && !(node instanceof U.AST_Function);
|
||||
return node instanceof U.AST_Statement && !(node instanceof U.AST_AsyncFunction || node instanceof U.AST_Function);
|
||||
}
|
||||
|
||||
function merge_sequence(array, node) {
|
||||
@@ -650,7 +675,15 @@ function wrap_with_console_log(node) {
|
||||
|
||||
function run_code(code, toplevel, result_cache, timeout) {
|
||||
var key = crypto.createHash("sha1").update(code).digest("base64");
|
||||
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
|
||||
var value = result_cache[key];
|
||||
if (!value) {
|
||||
var start = Date.now();
|
||||
result_cache[key] = value = {
|
||||
result: sandbox.run_code(code, toplevel, timeout),
|
||||
elapsed: Date.now() - start,
|
||||
};
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||
@@ -658,21 +691,19 @@ function compare_run_code(code, minify_options, result_cache, max_timeout) {
|
||||
if (minified.error) return minified;
|
||||
|
||||
var toplevel = sandbox.has_toplevel(minify_options);
|
||||
var elapsed = Date.now();
|
||||
var unminified_result = run_code(code, toplevel, result_cache, max_timeout);
|
||||
elapsed = Date.now() - elapsed;
|
||||
var timeout = Math.min(100 * elapsed, max_timeout);
|
||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout);
|
||||
var unminified = run_code(code, toplevel, result_cache, max_timeout);
|
||||
var timeout = Math.min(100 * unminified.elapsed, max_timeout);
|
||||
var minified_result = run_code(minified.code, toplevel, result_cache, timeout).result;
|
||||
|
||||
if (sandbox.same_stdout(unminified_result, minified_result)) {
|
||||
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
|
||||
if (sandbox.same_stdout(unminified.result, minified_result)) {
|
||||
return is_timed_out(unminified.result) && is_timed_out(minified_result) && {
|
||||
timed_out: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
unminified_result: unminified_result,
|
||||
unminified_result: unminified.result,
|
||||
minified_result: minified_result,
|
||||
elapsed: elapsed,
|
||||
elapsed: unminified.elapsed,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,17 +26,27 @@ var setupContext = new vm.Script([
|
||||
]).join("\n"));
|
||||
|
||||
function createContext() {
|
||||
var ctx = vm.createContext(Object.defineProperty({}, "console", { value: { log: log } }));
|
||||
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":
|
||||
case "function":
|
||||
return arg.toString();
|
||||
case "object":
|
||||
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);
|
||||
|
||||
@@ -1,11 +1,47 @@
|
||||
require("../../tools/exit");
|
||||
|
||||
var get = require("https").get;
|
||||
var parse = require("url").parse;
|
||||
var base = process.argv[2];
|
||||
var token = process.argv[3];
|
||||
|
||||
var base, token, run_number, eldest = true;
|
||||
exports.init = function(url, auth, num) {
|
||||
base = url;
|
||||
token = auth;
|
||||
run_number = 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) {
|
||||
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;
|
||||
read(workflow.jobs_url, function(reply) {
|
||||
if (!reply || !Array.isArray(reply.jobs)) return;
|
||||
if (!reply.jobs.every(function(job) {
|
||||
if (job.status == "completed") return true;
|
||||
remaining--;
|
||||
return found || workflow.event != "schedule";
|
||||
})) return;
|
||||
if (remaining >= 0) {
|
||||
next();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
||||
};
|
||||
|
||||
function read(url, callback) {
|
||||
var done = function(reply) {
|
||||
done = function() {};
|
||||
callback(reply);
|
||||
};
|
||||
var options = parse(url);
|
||||
options.headers = {
|
||||
"Authorization": "Token " + token,
|
||||
@@ -17,33 +53,15 @@ function read(url, callback) {
|
||||
response.on("data", function(chunk) {
|
||||
chunks.push(chunk);
|
||||
}).on("end", function() {
|
||||
callback(JSON.parse(chunks.join("")));
|
||||
var reply;
|
||||
try {
|
||||
reply = JSON.parse(chunks.join(""))
|
||||
} catch (e) {}
|
||||
done(reply);
|
||||
}).on("error", function() {
|
||||
done();
|
||||
});
|
||||
}).on("error", function() {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
var queued = 0, total = 0, earliest, now = Date.now();
|
||||
process.on("beforeExit", function() {
|
||||
if (queued > 3) {
|
||||
process.stdout.write("0");
|
||||
} else if (now - earliest > 0 && total > 1) {
|
||||
process.stdout.write(Math.min(20 * (now - earliest) / (total - 1), 6300000).toFixed(0));
|
||||
} else {
|
||||
process.stdout.write("3600000");
|
||||
}
|
||||
});
|
||||
read(base + "/actions/workflows/ufuzz.yml/runs?event=schedule", function(reply) {
|
||||
reply.workflow_runs.filter(function(workflow) {
|
||||
return /^(in_progress|queued|)$/.test(workflow.status);
|
||||
}).forEach(function(workflow) {
|
||||
read(workflow.jobs_url, function(reply) {
|
||||
reply.jobs.forEach(function(job) {
|
||||
if (job.status == "queued") queued++;
|
||||
total++;
|
||||
if (!job.started_at) return;
|
||||
var start = new Date(job.started_at);
|
||||
if (!(earliest < start)) earliest = start;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,39 +1,71 @@
|
||||
var actions = require("./actions");
|
||||
var child_process = require("child_process");
|
||||
|
||||
var ping = 5 * 60 * 1000;
|
||||
var period = +process.argv[2];
|
||||
var endTime = Date.now() + period;
|
||||
for (var i = 0; i < 2; i++) spawn(endTime);
|
||||
|
||||
function spawn(endTime) {
|
||||
var child = child_process.spawn("node", [
|
||||
"--max-old-space-size=2048",
|
||||
"test/ufuzz"
|
||||
], {
|
||||
stdio: [ "ignore", "pipe", "pipe" ]
|
||||
}).on("exit", respawn);
|
||||
var stdout = "";
|
||||
child.stdout.on("data", function(data) {
|
||||
stdout += data;
|
||||
var args = [
|
||||
"--max-old-space-size=2048",
|
||||
"test/ufuzz",
|
||||
];
|
||||
var iterations;
|
||||
switch (process.argv.length) {
|
||||
case 3:
|
||||
iterations = +process.argv[2];
|
||||
args.push(iterations);
|
||||
break;
|
||||
case 5:
|
||||
actions.init(process.argv[2], process.argv[3], +process.argv[4]);
|
||||
break;
|
||||
default:
|
||||
throw new Error("invalid parameters");
|
||||
}
|
||||
var tasks = [ run(), run() ];
|
||||
if (iterations) return;
|
||||
var alive = setInterval(function() {
|
||||
actions.should_stop(function() {
|
||||
clearInterval(alive);
|
||||
tasks.forEach(function(kill) {
|
||||
kill();
|
||||
});
|
||||
});
|
||||
var stderr = "";
|
||||
child.stderr.on("data", trap).pipe(process.stdout);
|
||||
var keepAlive = setInterval(function() {
|
||||
var end = stdout.lastIndexOf("\r");
|
||||
console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end));
|
||||
stdout = stdout.slice(end + 1);
|
||||
}, ping);
|
||||
var timer = setTimeout(function() {
|
||||
clearInterval(keepAlive);
|
||||
}, 8 * 60 * 1000);
|
||||
|
||||
function run() {
|
||||
var child, stdout, stderr, log;
|
||||
spawn();
|
||||
return function() {
|
||||
clearInterval(log);
|
||||
child.removeListener("exit", respawn);
|
||||
child.kill();
|
||||
}, endTime - Date.now());
|
||||
};
|
||||
|
||||
function spawn() {
|
||||
child = child_process.spawn("node", args, {
|
||||
stdio: [ "ignore", "pipe", "pipe" ]
|
||||
}).on("exit", respawn);
|
||||
stdout = "";
|
||||
child.stdout.on("data", function(data) {
|
||||
stdout += data;
|
||||
});
|
||||
stderr = "";
|
||||
child.stderr.on("data", trap).pipe(process.stdout);
|
||||
log = setInterval(function() {
|
||||
stdout = stdout.replace(/[^\r\n]+\r(?=[^\r\n]+\r)/g, "");
|
||||
var end = stdout.lastIndexOf("\r");
|
||||
if (end < 0) return;
|
||||
console.log(stdout.slice(0, end));
|
||||
stdout = stdout.slice(end + 1);
|
||||
}, 5 * 60 * 1000);
|
||||
}
|
||||
|
||||
function respawn() {
|
||||
console.log(stdout.replace(/[^\r\n]*\r/g, ""));
|
||||
clearInterval(keepAlive);
|
||||
clearTimeout(timer);
|
||||
spawn(endTime);
|
||||
clearInterval(log);
|
||||
if (!iterations) {
|
||||
spawn();
|
||||
} else if (process.exitCode) {
|
||||
tasks.forEach(function(kill) {
|
||||
kill();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function trap(data) {
|
||||
|
||||
Reference in New Issue
Block a user